src: enable more detailed memory tracking

This will enable more detailed heap snapshots based on
a newer V8 API.

This commit itself is not tied to that API and could
be backported.

PR-URL: https://github.com/nodejs/node/pull/21742
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Anna Henningsen committed 2018-07-13 19:53:15 +02:00
1 parent 36cc5f5caf
commit 57e301539b
46 files changed
+566 -91

No files matched your search

+2
View File
@@ -423,6 +423,8 @@
'src/node_revert.h',
'src/node_i18n.h',
'src/node_worker.h',
'src/memory_tracker.h',
'src/memory_tracker-inl.h',
'src/pipe_wrap.h',
'src/tty_wrap.h',
'src/tcp_wrap.h',
+17 -4
View File
@@ -76,14 +76,22 @@ class RetainedAsyncInfo: public RetainedObjectInfo {
private:
const char* label_;
const AsyncWrap* wrap_;
const int length_;
const size_t length_;
};
static int OwnMemory(AsyncWrap* async_wrap) {
MemoryTracker tracker;
tracker.set_track_only_self(true);
tracker.Track(async_wrap);
return tracker.accumulated_size();
}
RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap)
: label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]),
wrap_(wrap),
length_(wrap->self_size()) {
length_(OwnMemory(wrap)) {
}
@@ -147,7 +155,9 @@ struct AsyncWrapObject : public AsyncWrap {
inline AsyncWrapObject(Environment* env, Local<Object> object,
ProviderType type) : AsyncWrap(env, object, type) {}
inline size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};
@@ -252,7 +262,10 @@ class PromiseWrap : public AsyncWrap {
: AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) {
MakeWeak();
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
static constexpr int kPromiseField = 1;
static constexpr int kIsChainedPromiseField = 2;
-1
View File
@@ -173,7 +173,6 @@ class AsyncWrap : public BaseObject {
int argc,
v8::Local<v8::Value>* argv);
virtual size_t self_size() const = 0;
virtual std::string diagnostic_name() const;
static void WeakCallback(const v8::WeakCallbackInfo<DestroyParam> &info);
+2 -8
View File
@@ -61,11 +61,11 @@ Persistent<v8::Object>& BaseObject::persistent() {
}
v8::Local<v8::Object> BaseObject::object() {
v8::Local<v8::Object> BaseObject::object() const {
return PersistentToLocal(env_->isolate(), persistent_handle_);
}
v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) {
v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) const {
v8::Local<v8::Object> handle = object();
#ifdef DEBUG
CHECK_EQ(handle->CreationContext()->GetIsolate(), isolate);
@@ -91,12 +91,6 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
}
void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
delete self;
}
void BaseObject::MakeWeak() {
persistent_handle_.SetWeak(
this,
+9 -4
View File
@@ -25,6 +25,7 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "node_persistent.h"
#include "memory_tracker-inl.h"
#include "v8.h"
#include <type_traits> // std::remove_reference
@@ -32,7 +33,7 @@ namespace node {
class Environment;
class BaseObject {
class BaseObject : public MemoryRetainer {
public:
// Associates this object with `object`. It uses the 0th internal field for
// that, and in particular aborts if there is no such field.
@@ -41,11 +42,11 @@ class BaseObject {
// Returns the wrapped object. Returns an empty handle when
// persistent.IsEmpty() is true.
inline v8::Local<v8::Object> object();
inline v8::Local<v8::Object> object() const;
// Same as the above, except it additionally verifies that this object
// is associated with the passed Isolate in debug mode.
inline v8::Local<v8::Object> object(v8::Isolate* isolate);
inline v8::Local<v8::Object> object(v8::Isolate* isolate) const;
inline Persistent<v8::Object>& persistent();
@@ -75,7 +76,9 @@ class BaseObject {
private:
BaseObject();
static inline void DeleteMe(void* data);
v8::Local<v8::Object> WrappedObject() const override;
bool IsRootNode() const override;
static void DeleteMe(void* data);
// persistent_handle_ needs to be at a fixed offset from the start of the
// class because it is used by src/node_postmortem_metadata.cc to calculate
@@ -83,6 +86,8 @@ class BaseObject {
// position of members in memory are predictable. For more information please
// refer to `doc/guides/node-postmortem-support.md`
friend int GenDebugSymbols();
friend class Environment;
Persistent<v8::Object> persistent_handle_;
Environment* env_;
};
+59 -18
View File
@@ -121,10 +121,12 @@ inline const char* ToErrorCodeString(int status) {
class ChannelWrap;
struct node_ares_task {
struct node_ares_task : public MemoryRetainer {
ChannelWrap* channel;
ares_socket_t sock;
uv_poll_t poll_watcher;
void MemoryInfo(MemoryTracker* tracker) const override;
};
struct TaskHash {
@@ -167,7 +169,12 @@ class ChannelWrap : public AsyncWrap {
inline int active_query_count() { return active_query_count_; }
inline node_ares_task_list* task_list() { return &task_list_; }
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
if (timer_handle_ != nullptr)
tracker->TrackFieldWithSize("timer handle", sizeof(*timer_handle_));
tracker->TrackField("task list", task_list_);
}
static void AresTimeout(uv_timer_t* handle);
@@ -181,6 +188,11 @@ class ChannelWrap : public AsyncWrap {
node_ares_task_list task_list_;
};
void node_ares_task::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
tracker->TrackField("channel", channel);
}
ChannelWrap::ChannelWrap(Environment* env,
Local<Object> object)
: AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
@@ -209,7 +221,10 @@ class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
Local<Object> req_wrap_obj,
bool verbatim);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
bool verbatim() const { return verbatim_; }
private:
@@ -228,7 +243,9 @@ class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> {
public:
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};
GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env,
@@ -270,13 +287,13 @@ void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
void ares_poll_close_cb(uv_poll_t* watcher) {
node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher);
free(task);
delete task;
}
/* Allocates and returns a new node_ares_task */
node_ares_task* ares_task_create(ChannelWrap* channel, ares_socket_t sock) {
auto task = node::UncheckedMalloc<node_ares_task>(1);
auto task = new node_ares_task();
if (task == nullptr) {
/* Out of memory. */
@@ -1172,7 +1189,9 @@ class QueryAnyWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1349,7 +1368,9 @@ class QueryAWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1393,7 +1414,9 @@ class QueryAaaaWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1437,7 +1460,9 @@ class QueryCnameWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1468,7 +1493,9 @@ class QueryMxWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1499,7 +1526,9 @@ class QueryNsWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1530,7 +1559,9 @@ class QueryTxtWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1560,7 +1591,9 @@ class QuerySrvWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1589,7 +1622,9 @@ class QueryPtrWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1620,7 +1655,9 @@ class QueryNaptrWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1650,7 +1687,9 @@ class QuerySoaWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(unsigned char* buf, int len) override {
@@ -1729,7 +1768,9 @@ class GetHostByAddrWrap: public QueryWrap {
return 0;
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void Parse(struct hostent* host) override {
+3 -1
View File
@@ -16,7 +16,9 @@ class ConnectWrap : public ReqWrap<uv_connect_t> {
v8::Local<v8::Object> req_wrap_obj,
AsyncWrap::ProviderType provider);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};
} // namespace node
+14
View File
@@ -734,4 +734,18 @@ void Environment::stop_sub_worker_contexts() {
}
}
// Not really any better place than env.cc at this moment.
void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
delete self;
}
Local<Object> BaseObject::WrappedObject() const {
return object();
}
bool BaseObject::IsRootNode() const {
return !persistent_handle_.IsWeak();
}
} // namespace node
+4 -1
View File
@@ -56,7 +56,10 @@ class FSEventWrap: public HandleWrap {
static void New(const FunctionCallbackInfo<Value>& args);
static void Start(const FunctionCallbackInfo<Value>& args);
static void GetInitialized(const FunctionCallbackInfo<Value>& args);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static const encoding kDefaultEncoding = UTF8;
+5 -1
View File
@@ -103,7 +103,11 @@ class JSBindingsConnection : public AsyncWrap {
}
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("callback", callback_);
tracker->TrackFieldWithSize("session", sizeof(*session_));
}
private:
std::unique_ptr<InspectorSession> session_;
+3 -1
View File
@@ -27,7 +27,9 @@ class JSStream : public AsyncWrap, public StreamBase {
size_t count,
uv_stream_t* send_handle) override;
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
JSStream(Environment* env, v8::Local<v8::Object> obj);
+107
View File
@@ -0,0 +1,107 @@
#ifndef SRC_MEMORY_TRACKER_INL_H_
#define SRC_MEMORY_TRACKER_INL_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "memory_tracker.h"
namespace node {
template <typename T>
void MemoryTracker::TrackThis(const T* obj) {
accumulated_size_ += sizeof(T);
}
void MemoryTracker::TrackFieldWithSize(const char* name, size_t size) {
accumulated_size_ += size;
}
void MemoryTracker::TrackField(const char* name, const MemoryRetainer& value) {
TrackField(name, &value);
}
void MemoryTracker::TrackField(const char* name, const MemoryRetainer* value) {
if (track_only_self_ || value == nullptr || seen_.count(value) > 0) return;
seen_.insert(value);
Track(value);
}
template <typename T>
void MemoryTracker::TrackField(const char* name,
const std::unique_ptr<T>& value) {
TrackField(name, value.get());
}
template <typename T, typename Iterator>
void MemoryTracker::TrackField(const char* name, const T& value) {
if (value.begin() == value.end()) return;
size_t index = 0;
for (Iterator it = value.begin(); it != value.end(); ++it)
TrackField(std::to_string(index++).c_str(), *it);
}
template <typename T>
void MemoryTracker::TrackField(const char* name, const std::queue<T>& value) {
struct ContainerGetter : public std::queue<T> {
static const typename std::queue<T>::container_type& Get(
const std::queue<T>& value) {
return value.*&ContainerGetter::c;
}
};
const auto& container = ContainerGetter::Get(value);
TrackField(name, container);
}
template <typename T, typename test_for_number, typename dummy>
void MemoryTracker::TrackField(const char* name, const T& value) {
// For numbers, creating new nodes is not worth the overhead.
TrackFieldWithSize(name, sizeof(T));
}
template <typename T, typename U>
void MemoryTracker::TrackField(const char* name, const std::pair<T, U>& value) {
TrackField("first", value.first);
TrackField("second", value.second);
}
template <typename T>
void MemoryTracker::TrackField(const char* name,
const std::basic_string<T>& value) {
TrackFieldWithSize(name, value.size() * sizeof(T));
}
template <typename T, typename Traits>
void MemoryTracker::TrackField(const char* name,
const v8::Persistent<T, Traits>& value) {
}
template <typename T>
void MemoryTracker::TrackField(const char* name, const v8::Local<T>& value) {
}
template <typename T>
void MemoryTracker::TrackField(const char* name,
const MallocedBuffer<T>& value) {
TrackFieldWithSize(name, value.size);
}
void MemoryTracker::TrackField(const char* name, const uv_buf_t& value) {
TrackFieldWithSize(name, value.len);
}
template <class NativeT, class V8T>
void MemoryTracker::TrackField(const char* name,
const AliasedBuffer<NativeT, V8T>& value) {
TrackField(name, value.GetJSArray());
}
void MemoryTracker::Track(const MemoryRetainer* value) {
value->MemoryInfo(this);
}
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_MEMORY_TRACKER_INL_H_
+87
View File
@@ -0,0 +1,87 @@
#ifndef SRC_MEMORY_TRACKER_H_
#define SRC_MEMORY_TRACKER_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include <unordered_set>
#include <queue>
#include <limits>
#include <uv.h>
#include <aliased_buffer.h>
namespace node {
class MemoryTracker;
namespace crypto {
class NodeBIO;
}
class MemoryRetainer {
public:
virtual ~MemoryRetainer() {}
// Subclasses should implement this to provide information for heap snapshots.
virtual void MemoryInfo(MemoryTracker* tracker) const = 0;
virtual v8::Local<v8::Object> WrappedObject() const {
return v8::Local<v8::Object>();
}
virtual bool IsRootNode() const { return false; }
};
class MemoryTracker {
public:
template <typename T>
inline void TrackThis(const T* obj);
inline void TrackFieldWithSize(const char* name, size_t size);
inline void TrackField(const char* name, const MemoryRetainer& value);
inline void TrackField(const char* name, const MemoryRetainer* value);
template <typename T>
inline void TrackField(const char* name, const std::unique_ptr<T>& value);
template <typename T, typename Iterator = typename T::const_iterator>
inline void TrackField(const char* name, const T& value);
template <typename T>
inline void TrackField(const char* name, const std::queue<T>& value);
template <typename T>
inline void TrackField(const char* name, const std::basic_string<T>& value);
template <typename T, typename test_for_number =
typename std::enable_if<
std::numeric_limits<T>::is_specialized, bool>::type,
typename dummy = bool>
inline void TrackField(const char* name, const T& value);
template <typename T, typename U>
inline void TrackField(const char* name, const std::pair<T, U>& value);
template <typename T, typename Traits>
inline void TrackField(const char* name,
const v8::Persistent<T, Traits>& value);
template <typename T>
inline void TrackField(const char* name, const v8::Local<T>& value);
template <typename T>
inline void TrackField(const char* name, const MallocedBuffer<T>& value);
inline void TrackField(const char* name, const uv_buf_t& value);
template <class NativeT, class V8T>
inline void TrackField(const char* name,
const AliasedBuffer<NativeT, V8T>& value);
inline void Track(const MemoryRetainer* value);
inline size_t accumulated_size() const { return accumulated_size_; }
inline void set_track_only_self(bool value) { track_only_self_ = value; }
inline MemoryTracker() {}
private:
bool track_only_self_ = false;
size_t accumulated_size_ = 0;
std::unordered_set<const MemoryRetainer*> seen_;
};
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_MEMORY_TRACKER_H_
+6
View File
@@ -33,6 +33,12 @@ class ModuleWrap : public BaseObject {
v8::Local<v8::Module> module,
v8::Local<v8::Object> meta);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("url", url_);
tracker->TrackField("resolve_cache", resolve_cache_);
}
private:
ModuleWrap(Environment* env,
v8::Local<v8::Object> object,
+4
View File
@@ -588,6 +588,10 @@ class ContextifyScript : public BaseObject {
private:
Persistent<UnboundScript> script_;
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
public:
static void Init(Environment* env, Local<Object> target) {
HandleScope scope(env->isolate());
+1
View File
@@ -49,6 +49,7 @@ class ContextifyContext {
context()->GetEmbedderData(ContextEmbedderIndex::kSandboxObject));
}
template <typename T>
static ContextifyContext* Get(const v8::PropertyCallbackInfo<T>& args);
+2
View File
@@ -4582,6 +4582,8 @@ bool ECDH::IsKeyPairValid() {
}
// TODO(addaleax): If there is an `AsyncWrap`, it currently has no access to
// this object. This makes proper reporting of memory usage impossible.
struct CryptoJob : public ThreadPoolWork {
Environment* const env;
std::unique_ptr<AsyncWrap> async_wrap;
+28
View File
@@ -105,6 +105,10 @@ class SecureContext : public BaseObject {
static void Initialize(Environment* env, v8::Local<v8::Object> target);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
SSLCtxPointer ctx_;
X509Pointer cert_;
X509Pointer issuer_;
@@ -337,6 +341,10 @@ class CipherBase : public BaseObject {
public:
static void Initialize(Environment* env, v8::Local<v8::Object> target);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
enum CipherKind {
kCipher,
@@ -407,6 +415,10 @@ class Hmac : public BaseObject {
public:
static void Initialize(Environment* env, v8::Local<v8::Object> target);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void HmacInit(const char* hash_type, const char* key, int key_len);
bool HmacUpdate(const char* data, int len);
@@ -430,6 +442,10 @@ class Hash : public BaseObject {
public:
static void Initialize(Environment* env, v8::Local<v8::Object> target);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
bool HashInit(const char* hash_type);
bool HashUpdate(const char* data, int len);
@@ -469,6 +485,10 @@ class SignBase : public BaseObject {
Error Init(const char* sign_type);
Error Update(const char* data, int len);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
void CheckThrow(Error error);
@@ -581,6 +601,10 @@ class DiffieHellman : public BaseObject {
MakeWeak();
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
const BIGNUM* (*get_field)(const DH*),
@@ -606,6 +630,10 @@ class ECDH : public BaseObject {
char* data,
size_t len);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
ECDH(Environment* env, v8::Local<v8::Object> wrap, ECKeyPointer&& key)
: BaseObject(env, wrap),
+6 -1
View File
@@ -32,7 +32,7 @@
namespace node {
namespace crypto {
class NodeBIO {
class NodeBIO : public MemoryRetainer {
public:
NodeBIO() : env_(nullptr),
initial_(kInitialBufferLength),
@@ -110,6 +110,11 @@ class NodeBIO {
static NodeBIO* FromBIO(BIO* bio);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackFieldWithSize("buffer", length_);
}
private:
static int New(BIO* bio);
static int Free(BIO* bio);
+23 -4
View File
@@ -66,7 +66,6 @@ class FSReqBase : public ReqWrap<uv_fs_t> {
const char* data() const { return has_data_ ? *buffer_ : nullptr; }
enum encoding encoding() const { return encoding_; }
size_t self_size() const override { return sizeof(*this); }
bool use_bigint() const { return use_bigint_; }
private:
@@ -92,6 +91,10 @@ class FSReqWrap : public FSReqBase {
void ResolveStat(const uv_stat_t* stat) override;
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
};
@@ -150,6 +153,11 @@ class FSReqPromise : public FSReqBase {
args.GetReturnValue().Set(resolver->GetPromise());
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("stats_field_array", stats_field_array_);
}
private:
bool finished_ = false;
AliasedBuffer<NativeT, V8T> stats_field_array_;
@@ -184,7 +192,10 @@ class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("buffer", buffer_);
}
private:
FileHandle* file_handle_;
@@ -205,7 +216,6 @@ class FileHandle : public AsyncWrap, public StreamBase {
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
int fd() const { return fd_; }
size_t self_size() const override { return sizeof(*this); }
// Will asynchronously close the FD and return a Promise that will
// be resolved once closing is complete.
@@ -233,6 +243,11 @@ class FileHandle : public AsyncWrap, public StreamBase {
return UV_ENOSYS; // Not implemented (yet).
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("current_read", current_read_);
}
private:
// Synchronous close that emits a warning
void Close();
@@ -259,7 +274,11 @@ class FileHandle : public AsyncWrap, public StreamBase {
FileHandle* file_handle();
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("promise", promise_);
tracker->TrackField("ref", ref_);
}
void Resolve();
+21 -6
View File
@@ -737,7 +737,7 @@ inline void Http2Session::AddStream(Http2Stream* stream) {
size_t size = streams_.size();
if (size > statistics_.max_concurrent_streams)
statistics_.max_concurrent_streams = size;
IncrementCurrentSessionMemory(stream->self_size());
IncrementCurrentSessionMemory(sizeof(*stream));
}
@@ -745,7 +745,7 @@ inline void Http2Session::RemoveStream(Http2Stream* stream) {
if (streams_.empty() || stream == nullptr)
return; // Nothing to remove, item was never added?
streams_.erase(stream->id());
DecrementCurrentSessionMemory(stream->self_size());
DecrementCurrentSessionMemory(sizeof(*stream));
}
// Used as one of the Padding Strategy functions. Will attempt to ensure
@@ -2694,7 +2694,7 @@ Http2Session::Http2Ping* Http2Session::PopPing() {
if (!outstanding_pings_.empty()) {
ping = outstanding_pings_.front();
outstanding_pings_.pop();
DecrementCurrentSessionMemory(ping->self_size());
DecrementCurrentSessionMemory(sizeof(*ping));
}
return ping;
}
@@ -2703,7 +2703,7 @@ bool Http2Session::AddPing(Http2Session::Http2Ping* ping) {
if (outstanding_pings_.size() == max_outstanding_pings_)
return false;
outstanding_pings_.push(ping);
IncrementCurrentSessionMemory(ping->self_size());
IncrementCurrentSessionMemory(sizeof(*ping));
return true;
}
@@ -2712,7 +2712,7 @@ Http2Session::Http2Settings* Http2Session::PopSettings() {
if (!outstanding_settings_.empty()) {
settings = outstanding_settings_.front();
outstanding_settings_.pop();
DecrementCurrentSessionMemory(settings->self_size());
DecrementCurrentSessionMemory(sizeof(*settings));
}
return settings;
}
@@ -2721,7 +2721,7 @@ bool Http2Session::AddSettings(Http2Session::Http2Settings* settings) {
if (outstanding_settings_.size() == max_outstanding_settings_)
return false;
outstanding_settings_.push(settings);
IncrementCurrentSessionMemory(settings->self_size());
IncrementCurrentSessionMemory(sizeof(*settings));
return true;
}
@@ -2766,6 +2766,21 @@ void Http2Session::Http2Ping::Done(bool ack, const uint8_t* payload) {
}
void nghttp2_stream_write::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
if (req_wrap != nullptr)
tracker->TrackField("req_wrap", req_wrap->GetAsyncWrap());
tracker->TrackField("buf", buf);
}
void nghttp2_header::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
tracker->TrackFieldWithSize("name", nghttp2_rcbuf_get_buf(name).len);
tracker->TrackFieldWithSize("value", nghttp2_rcbuf_get_buf(value).len);
}
// Set up the process.binding('http2') binding.
void Initialize(Local<Object> target,
Local<Value> unused,
+31 -6
View File
@@ -83,19 +83,23 @@ enum nghttp2_stream_options {
STREAM_OPTION_GET_TRAILERS = 0x2,
};
struct nghttp2_stream_write {
struct nghttp2_stream_write : public MemoryRetainer {
WriteWrap* req_wrap = nullptr;
uv_buf_t buf;
inline explicit nghttp2_stream_write(uv_buf_t buf_) : buf(buf_) {}
inline nghttp2_stream_write(WriteWrap* req, uv_buf_t buf_) :
req_wrap(req), buf(buf_) {}
void MemoryInfo(MemoryTracker* tracker) const override;
};
struct nghttp2_header {
struct nghttp2_header : public MemoryRetainer {
nghttp2_rcbuf* name = nullptr;
nghttp2_rcbuf* value = nullptr;
uint8_t flags = 0;
void MemoryInfo(MemoryTracker* tracker) const override;
};
@@ -617,7 +621,12 @@ class Http2Stream : public AsyncWrap,
int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
uv_stream_t* send_handle) override;
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("current_headers", current_headers_);
tracker->TrackField("queue", queue_);
}
std::string diagnostic_name() const override;
// JavaScript API
@@ -793,7 +802,17 @@ class Http2Session : public AsyncWrap, public StreamListener {
// Write data to the session
ssize_t Write(const uv_buf_t* bufs, size_t nbufs);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("streams", streams_);
tracker->TrackField("outstanding_pings", outstanding_pings_);
tracker->TrackField("outstanding_settings", outstanding_settings_);
tracker->TrackField("outgoing_buffers", outgoing_buffers_);
tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size());
tracker->TrackFieldWithSize("pending_rst_streams",
pending_rst_streams_.size() * sizeof(int32_t));
}
std::string diagnostic_name() const override;
// Schedule an RstStream for after the current write finishes.
@@ -1109,7 +1128,10 @@ class Http2Session::Http2Ping : public AsyncWrap {
public:
explicit Http2Ping(Http2Session* session);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("session", session_);
}
void Send(uint8_t* payload);
void Done(bool ack, const uint8_t* payload = nullptr);
@@ -1129,7 +1151,10 @@ class Http2Session::Http2Settings : public AsyncWrap {
explicit Http2Settings(Environment* env);
explicit Http2Settings(Http2Session* session);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("session", session_);
}
void Send();
void Done(bool ack);
+3 -2
View File
@@ -155,8 +155,9 @@ class Parser : public AsyncWrap, public StreamListener {
}
size_t self_size() const override {
return sizeof(*this);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("current_buffer", current_buffer_);
}
+4
View File
@@ -250,6 +250,10 @@ class ConverterObject : public BaseObject, Converter {
}
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
protected:
ConverterObject(Environment* env,
v8::Local<v8::Object> wrap,
+14 -8
View File
@@ -325,6 +325,14 @@ Maybe<bool> Message::Serialize(Environment* env,
return Just(true);
}
void Message::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
tracker->TrackField("array_buffer_contents", array_buffer_contents_);
tracker->TrackFieldWithSize("shared_array_buffers",
shared_array_buffers_.size() * sizeof(shared_array_buffers_[0]));
tracker->TrackField("message_ports", message_ports_);
}
MessagePortData::MessagePortData(MessagePort* owner) : owner_(owner) { }
MessagePortData::~MessagePortData() {
@@ -332,6 +340,12 @@ MessagePortData::~MessagePortData() {
Disentangle();
}
void MessagePortData::MemoryInfo(MemoryTracker* tracker) const {
Mutex::ScopedLock lock(mutex_);
tracker->TrackThis(this);
tracker->TrackField("incoming_messages", incoming_messages_);
}
void MessagePortData::AddToIncomingQueue(Message&& message) {
// This function will be called by other threads.
Mutex::ScopedLock lock(mutex_);
@@ -688,14 +702,6 @@ void MessagePort::Drain(const FunctionCallbackInfo<Value>& args) {
port->OnMessage();
}
size_t MessagePort::self_size() const {
Mutex::ScopedLock lock(data_->mutex_);
size_t sz = sizeof(*this) + sizeof(*data_);
for (const Message& msg : data_->incoming_messages_)
sz += sizeof(msg) + msg.main_message_buf_.size;
return sz;
}
void MessagePort::Entangle(MessagePort* a, MessagePort* b) {
Entangle(a, b->data_.get());
}
+10 -3
View File
@@ -15,7 +15,7 @@ class MessagePortData;
class MessagePort;
// Represents a single communication message.
class Message {
class Message : public MemoryRetainer {
public:
explicit Message(MallocedBuffer<char>&& payload = MallocedBuffer<char>());
@@ -55,6 +55,8 @@ class Message {
return message_ports_;
}
void MemoryInfo(MemoryTracker* tracker) const override;
private:
MallocedBuffer<char> main_message_buf_;
std::vector<MallocedBuffer<char>> array_buffer_contents_;
@@ -66,7 +68,7 @@ class Message {
// This contains all data for a `MessagePort` instance that is not tied to
// a specific Environment/Isolate/event loop, for easier transfer between those.
class MessagePortData {
class MessagePortData : public MemoryRetainer {
public:
explicit MessagePortData(MessagePort* owner);
~MessagePortData();
@@ -94,6 +96,8 @@ class MessagePortData {
// which can happen on either side of a worker.
void Disentangle();
void MemoryInfo(MemoryTracker* tracker) const override;
private:
// After disentangling this message port, the owner handle (if any)
// is asynchronously triggered, so that it can close down naturally.
@@ -178,7 +182,10 @@ class MessagePort : public HandleWrap {
// NULL pointer to the C++ MessagePort object is also detached.
inline bool IsDetached() const;
size_t self_size() const override;
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("data", data_);
}
private:
void OnClose() override;
+10
View File
@@ -52,6 +52,11 @@ class SerializerContext : public BaseObject,
static void WriteUint64(const FunctionCallbackInfo<Value>& args);
static void WriteDouble(const FunctionCallbackInfo<Value>& args);
static void WriteRawBytes(const FunctionCallbackInfo<Value>& args);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
ValueSerializer serializer_;
};
@@ -76,6 +81,11 @@ class DeserializerContext : public BaseObject,
static void ReadUint64(const FunctionCallbackInfo<Value>& args);
static void ReadDouble(const FunctionCallbackInfo<Value>& args);
static void ReadRawBytes(const FunctionCallbackInfo<Value>& args);
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
const uint8_t* data_;
const size_t length_;
+3 -1
View File
@@ -44,7 +44,9 @@ class StatWatcher : public HandleWrap {
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static void Callback(uv_fs_poll_t* handle,
+5
View File
@@ -27,6 +27,11 @@ class NodeCategorySet : public BaseObject {
const std::set<std::string>& GetCategories() { return categories_; }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackField("categories", categories_);
}
private:
NodeCategorySet(Environment* env,
Local<Object> wrap,
-4
View File
@@ -403,10 +403,6 @@ void Worker::Exit(int code) {
}
}
size_t Worker::self_size() const {
return sizeof(*this);
}
namespace {
// Return the MessagePort that is global for this Environment and communicates
+8 -1
View File
@@ -25,7 +25,14 @@ class Worker : public AsyncWrap {
// Wait for the worker thread to stop (in a blocking manner).
void JoinThread();
size_t self_size() const override;
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackFieldWithSize("isolate_data", sizeof(IsolateData));
tracker->TrackFieldWithSize("env", sizeof(Environment));
tracker->TrackFieldWithSize("thread_exit_async", sizeof(uv_async_t));
tracker->TrackField("parent_port", parent_port_);
}
bool is_stopped() const;
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+6 -1
View File
@@ -646,7 +646,12 @@ class ZCtx : public AsyncWrap, public ThreadPoolWork {
}
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackFieldWithSize("dictionary", dictionary_len_);
tracker->TrackFieldWithSize("zlib memory",
zlib_memory_ + unreported_allocations_);
}
private:
void Ref() {
+3 -1
View File
@@ -45,7 +45,9 @@ class PipeWrap : public ConnectionWrap<PipeWrap, uv_pipe_t> {
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
PipeWrap(Environment* env,
+3 -1
View File
@@ -66,7 +66,9 @@ class ProcessWrap : public HandleWrap {
target->Set(processString, constructor->GetFunction());
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static void New(const FunctionCallbackInfo<Value>& args) {
+4
View File
@@ -47,6 +47,10 @@ class SABLifetimePartner : public BaseObject {
MakeWeak();
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
SharedArrayBufferMetadataReference reference;
};
+3 -1
View File
@@ -60,7 +60,9 @@ class SignalWrap : public HandleWrap {
target->Set(signalString, constructor->GetFunction());
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static void New(const FunctionCallbackInfo<Value>& args) {
+9 -2
View File
@@ -346,7 +346,10 @@ class SimpleShutdownWrap : public ShutdownWrap, public OtherBase {
v8::Local<v8::Object> req_wrap_obj);
AsyncWrap* GetAsyncWrap() override { return this; }
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};
template <typename OtherBase>
@@ -356,7 +359,11 @@ class SimpleWriteWrap : public WriteWrap, public OtherBase {
v8::Local<v8::Object> req_wrap_obj);
AsyncWrap* GetAsyncWrap() override { return this; }
size_t self_size() const override { return sizeof(*this) + StorageSize(); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
tracker->TrackFieldWithSize("storage", StorageSize());
}
};
} // namespace node
+3 -1
View File
@@ -18,7 +18,9 @@ class StreamPipe : public AsyncWrap {
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Unpipe(const v8::FunctionCallbackInfo<v8::Value>& args);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
StreamBase* source();
+3 -1
View File
@@ -44,7 +44,9 @@ class TCPWrap : public ConnectionWrap<TCPWrap, uv_tcp_t> {
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context);
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
typedef uv_tcp_t HandleType;
+3 -1
View File
@@ -67,7 +67,9 @@ class TimerWrap : public HandleWrap {
->GetFunction(env->context()).ToLocalChecked()).FromJust();
}
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
static void SetupTimers(const FunctionCallbackInfo<Value>& args) {
+9
View File
@@ -864,6 +864,15 @@ void TLSWrap::GetWriteQueueSize(const FunctionCallbackInfo<Value>& info) {
}
void TLSWrap::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
tracker->TrackField("error", error_);
tracker->TrackField("pending_cleartext_input", pending_cleartext_input_);
tracker->TrackField("enc_in", crypto::NodeBIO::FromBIO(enc_in_));
tracker->TrackField("enc_out", crypto::NodeBIO::FromBIO(enc_out_));
}
void TLSWrap::Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
+1 -1
View File
@@ -76,7 +76,7 @@ class TLSWrap : public AsyncWrap,
void NewSessionDoneCb();
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override;
protected:
inline StreamBase* underlying_stream() {
+3 -1
View File
@@ -38,7 +38,9 @@ class TTYWrap : public LibuvStreamWrap {
uv_tty_t* UVHandle();
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
TTYWrap(Environment* env,
+5 -1
View File
@@ -55,7 +55,11 @@ class SendWrap : public ReqWrap<uv_udp_send_t> {
SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
inline bool have_callback() const;
size_t msg_size;
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
const bool have_callback_;
};
+3 -1
View File
@@ -64,7 +64,9 @@ class UDPWrap: public HandleWrap {
SocketType type);
uv_udp_t* UVHandle();
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
private:
typedef uv_udp_t HandleType;
+17 -3
View File
@@ -34,7 +34,9 @@ class DebugSymbolsTest : public EnvironmentTestFixture {};
class TestHandleWrap : public node::HandleWrap {
public:
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(node::MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
TestHandleWrap(node::Environment* env,
v8::Local<v8::Object> object,
@@ -48,7 +50,9 @@ class TestHandleWrap : public node::HandleWrap {
class TestReqWrap : public node::ReqWrap<uv_req_t> {
public:
size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(node::MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
TestReqWrap(node::Environment* env, v8::Local<v8::Object> object)
: node::ReqWrap<uv_req_t>(env,
@@ -67,6 +71,16 @@ TEST_F(DebugSymbolsTest, ExternalStringDataOffset) {
NODE_OFF_EXTSTR_DATA);
}
class DummyBaseObject : public node::BaseObject {
public:
DummyBaseObject(node::Environment* env, v8::Local<v8::Object> obj) :
BaseObject(env, obj) {}
void MemoryInfo(node::MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};
TEST_F(DebugSymbolsTest, BaseObjectPersistentHandle) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
@@ -77,7 +91,7 @@ TEST_F(DebugSymbolsTest, BaseObjectPersistentHandle) {
v8::Local<v8::Object> object =
obj_templ->NewInstance(env.context()).ToLocalChecked();
node::BaseObject obj(*env, object);
DummyBaseObject obj(*env, object);
auto expected = reinterpret_cast<uintptr_t>(&obj.persistent());
auto calculated = reinterpret_cast<uintptr_t>(&obj) +