summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-06-10 16:40:13 +0200
committerAnna Henningsen <anna@addaleax.net>2018-07-13 19:53:15 +0200
commit57e301539bff2599974b7269a56377330c9b730e (patch)
tree6f5c866728f22bbacb8dadb89a2c8a12e5b66508
parent36cc5f5caf52af895079d153a9131fe2b0c6b8f9 (diff)
downloadandroid-node-v8-57e301539bff2599974b7269a56377330c9b730e.tar.gz
android-node-v8-57e301539bff2599974b7269a56377330c9b730e.tar.bz2
android-node-v8-57e301539bff2599974b7269a56377330c9b730e.zip
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>
-rw-r--r--node.gyp2
-rw-r--r--src/async_wrap.cc21
-rw-r--r--src/async_wrap.h1
-rw-r--r--src/base_object-inl.h10
-rw-r--r--src/base_object.h13
-rw-r--r--src/cares_wrap.cc77
-rw-r--r--src/connect_wrap.h4
-rw-r--r--src/env.cc14
-rw-r--r--src/fs_event_wrap.cc5
-rw-r--r--src/inspector_js_api.cc6
-rw-r--r--src/js_stream.h4
-rw-r--r--src/memory_tracker-inl.h107
-rw-r--r--src/memory_tracker.h87
-rw-r--r--src/module_wrap.h6
-rw-r--r--src/node_contextify.cc4
-rw-r--r--src/node_contextify.h1
-rw-r--r--src/node_crypto.cc2
-rw-r--r--src/node_crypto.h28
-rw-r--r--src/node_crypto_bio.h7
-rw-r--r--src/node_file.h27
-rw-r--r--src/node_http2.cc27
-rw-r--r--src/node_http2.h37
-rw-r--r--src/node_http_parser.cc5
-rw-r--r--src/node_i18n.cc4
-rw-r--r--src/node_messaging.cc22
-rw-r--r--src/node_messaging.h13
-rw-r--r--src/node_serdes.cc10
-rw-r--r--src/node_stat_watcher.h4
-rw-r--r--src/node_trace_events.cc5
-rw-r--r--src/node_worker.cc4
-rw-r--r--src/node_worker.h9
-rw-r--r--src/node_zlib.cc7
-rw-r--r--src/pipe_wrap.h4
-rw-r--r--src/process_wrap.cc4
-rw-r--r--src/sharedarraybuffer_metadata.cc4
-rw-r--r--src/signal_wrap.cc4
-rw-r--r--src/stream_base.h11
-rw-r--r--src/stream_pipe.h4
-rw-r--r--src/tcp_wrap.h4
-rw-r--r--src/timer_wrap.cc4
-rw-r--r--src/tls_wrap.cc9
-rw-r--r--src/tls_wrap.h2
-rw-r--r--src/tty_wrap.h4
-rw-r--r--src/udp_wrap.cc6
-rw-r--r--src/udp_wrap.h4
-rw-r--r--test/cctest/test_node_postmortem_metadata.cc20
46 files changed, 566 insertions, 91 deletions
diff --git a/node.gyp b/node.gyp
index d89296246c..1ee29f1864 100644
--- a/node.gyp
+++ b/node.gyp
@@ -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',
diff --git a/src/async_wrap.cc b/src/async_wrap.cc
index 89e82b9ce3..e98dca3c56 100644
--- a/src/async_wrap.cc
+++ b/src/async_wrap.cc
@@ -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;
diff --git a/src/async_wrap.h b/src/async_wrap.h
index 64b74ac209..ef3a593489 100644
--- a/src/async_wrap.h
+++ b/src/async_wrap.h
@@ -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);
diff --git a/src/base_object-inl.h b/src/base_object-inl.h
index 06a2922397..d067a807cb 100644
--- a/src/base_object-inl.h
+++ b/src/base_object-inl.h
@@ -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,
diff --git a/src/base_object.h b/src/base_object.h
index 38291d598f..e0f3f27950 100644
--- a/src/base_object.h
+++ b/src/base_object.h
@@ -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_;
};
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index 3cf1d434d3..69a3d46668 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -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 {
diff --git a/src/connect_wrap.h b/src/connect_wrap.h
index 80eae7f9bb..587e4c6b05 100644
--- a/src/connect_wrap.h
+++ b/src/connect_wrap.h
@@ -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
diff --git a/src/env.cc b/src/env.cc
index 4d7008df36..30bc85559a 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -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
diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc
index 164614ae81..7587ace8e3 100644
--- a/src/fs_event_wrap.cc
+++ b/src/fs_event_wrap.cc
@@ -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;
diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc
index 96b064e495..9a74f4d109 100644
--- a/src/inspector_js_api.cc
+++ b/src/inspector_js_api.cc
@@ -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_;
diff --git a/src/js_stream.h b/src/js_stream.h
index b47a91a653..f3406ae83e 100644
--- a/src/js_stream.h
+++ b/src/js_stream.h
@@ -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);
diff --git a/src/memory_tracker-inl.h b/src/memory_tracker-inl.h
new file mode 100644
index 0000000000..758223492f
--- /dev/null
+++ b/src/memory_tracker-inl.h
@@ -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_
diff --git a/src/memory_tracker.h b/src/memory_tracker.h
new file mode 100644
index 0000000000..18822651f6
--- /dev/null
+++ b/src/memory_tracker.h
@@ -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_
diff --git a/src/module_wrap.h b/src/module_wrap.h
index 3969e2a378..2d6f5c49d8 100644
--- a/src/module_wrap.h
+++ b/src/module_wrap.h
@@ -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,
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 61c686ba00..e4b4fef3dc 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -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());
diff --git a/src/node_contextify.h b/src/node_contextify.h
index 2ebfef7f27..3d94fbc5c4 100644
--- a/src/node_contextify.h
+++ b/src/node_contextify.h
@@ -49,6 +49,7 @@ class ContextifyContext {
context()->GetEmbedderData(ContextEmbedderIndex::kSandboxObject));
}
+
template <typename T>
static ContextifyContext* Get(const v8::PropertyCallbackInfo<T>& args);
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 3df00baf65..5bceae0ce0 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -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;
diff --git a/src/node_crypto.h b/src/node_crypto.h
index 4587a96e72..7df2660c77 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -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),
diff --git a/src/node_crypto_bio.h b/src/node_crypto_bio.h
index 380a3a6b4c..dea010fa01 100644
--- a/src/node_crypto_bio.h
+++ b/src/node_crypto_bio.h
@@ -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);
diff --git a/src/node_file.h b/src/node_file.h
index a14a1b0f85..6b45dc8817 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -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();
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 0251777644..7a5e9ba23e 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -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,
diff --git a/src/node_http2.h b/src/node_http2.h
index d90c3aed66..cbed2a267d 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -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);
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc
index 7d96466c39..e8fc1f22e4 100644
--- a/src/node_http_parser.cc
+++ b/src/node_http_parser.cc
@@ -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_);
}
diff --git a/src/node_i18n.cc b/src/node_i18n.cc
index 4ace513810..288ad77f61 100644
--- a/src/node_i18n.cc
+++ b/src/node_i18n.cc
@@ -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,
diff --git a/src/node_messaging.cc b/src/node_messaging.cc
index 24a99c8bc6..20e0c7673b 100644
--- a/src/node_messaging.cc
+++ b/src/node_messaging.cc
@@ -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());
}
diff --git a/src/node_messaging.h b/src/node_messaging.h
index 62ae633b9e..da10300aed 100644
--- a/src/node_messaging.h
+++ b/src/node_messaging.h
@@ -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;
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
index 520b350199..4b2cc60b3f 100644
--- a/src/node_serdes.cc
+++ b/src/node_serdes.cc
@@ -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_;
diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h
index 45150de785..baf6bdc14e 100644
--- a/src/node_stat_watcher.h
+++ b/src/node_stat_watcher.h
@@ -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,
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
index 985c706dc4..0904311dad 100644
--- a/src/node_trace_events.cc
+++ b/src/node_trace_events.cc
@@ -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,
diff --git a/src/node_worker.cc b/src/node_worker.cc
index 6f325668b8..3768d80a9c 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -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
diff --git a/src/node_worker.h b/src/node_worker.h
index d802b5cfef..bd737d4800 100644
--- a/src/node_worker.h
+++ b/src/node_worker.h
@@ -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);
diff --git a/src/node_zlib.cc b/src/node_zlib.cc
index 169816d16f..031666e19a 100644
--- a/src/node_zlib.cc
+++ b/src/node_zlib.cc
@@ -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() {
diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h
index d6e45c28ff..9ed4f153ae 100644
--- a/src/pipe_wrap.h
+++ b/src/pipe_wrap.h
@@ -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,
diff --git a/src/process_wrap.cc b/src/process_wrap.cc
index 1931e8107f..b9a20c34a7 100644
--- a/src/process_wrap.cc
+++ b/src/process_wrap.cc
@@ -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) {
diff --git a/src/sharedarraybuffer_metadata.cc b/src/sharedarraybuffer_metadata.cc
index 86476a9f12..95fed87c8d 100644
--- a/src/sharedarraybuffer_metadata.cc
+++ b/src/sharedarraybuffer_metadata.cc
@@ -47,6 +47,10 @@ class SABLifetimePartner : public BaseObject {
MakeWeak();
}
+ void MemoryInfo(MemoryTracker* tracker) const override {
+ tracker->TrackThis(this);
+ }
+
SharedArrayBufferMetadataReference reference;
};
diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc
index e245ad924c..043aa3f10e 100644
--- a/src/signal_wrap.cc
+++ b/src/signal_wrap.cc
@@ -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) {
diff --git a/src/stream_base.h b/src/stream_base.h
index 4057806198..bbb20e52e1 100644
--- a/src/stream_base.h
+++ b/src/stream_base.h
@@ -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
diff --git a/src/stream_pipe.h b/src/stream_pipe.h
index 98d6dae11b..b72a60941b 100644
--- a/src/stream_pipe.h
+++ b/src/stream_pipe.h
@@ -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();
diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h
index 2ab50f1fdc..d6ca930609 100644
--- a/src/tcp_wrap.h
+++ b/src/tcp_wrap.h
@@ -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;
diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc
index 9da209bef4..c3962e83ee 100644
--- a/src/timer_wrap.cc
+++ b/src/timer_wrap.cc
@@ -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) {
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
index e731c0c130..0d0791b710 100644
--- a/src/tls_wrap.cc
+++ b/src/tls_wrap.cc
@@ -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) {
diff --git a/src/tls_wrap.h b/src/tls_wrap.h
index 1603d8919a..b45e379ca3 100644
--- a/src/tls_wrap.h
+++ b/src/tls_wrap.h
@@ -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() {
diff --git a/src/tty_wrap.h b/src/tty_wrap.h
index 91b07a570e..cca5650ddb 100644
--- a/src/tty_wrap.h
+++ b/src/tty_wrap.h
@@ -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,
diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc
index 2ef6732213..e5243319a5 100644
--- a/src/udp_wrap.cc
+++ b/src/udp_wrap.cc
@@ -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_;
};
diff --git a/src/udp_wrap.h b/src/udp_wrap.h
index 01eb8b961f..3792bcc459 100644
--- a/src/udp_wrap.h
+++ b/src/udp_wrap.h
@@ -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;
diff --git a/test/cctest/test_node_postmortem_metadata.cc b/test/cctest/test_node_postmortem_metadata.cc
index b911a92c0d..e9acd629f3 100644
--- a/test/cctest/test_node_postmortem_metadata.cc
+++ b/test/cctest/test_node_postmortem_metadata.cc
@@ -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) +