mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
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:
46 files changed
+566
-91
No files matched your search
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -49,6 +49,7 @@ class ContextifyContext {
|
||||
context()->GetEmbedderData(ContextEmbedderIndex::kSandboxObject));
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static ContextifyContext* Get(const v8::PropertyCallbackInfo<T>& args);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -47,6 +47,10 @@ class SABLifetimePartner : public BaseObject {
|
||||
MakeWeak();
|
||||
}
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackThis(this);
|
||||
}
|
||||
|
||||
SharedArrayBufferMetadataReference reference;
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) +
|
||||
|
||||
Reference in new issue
Block a user