src: implement MemoryRetainer in Environment · nodejs/node@f59ec2a (original) (raw)

`@@ -112,6 +112,29 @@ IsolateData::IsolateData(Isolate* isolate,

`

112

112

`#undef V

`

113

113

`}

`

114

114

``

``

115

`+

void IsolateData::MemoryInfo(MemoryTracker* tracker) const {

`

``

116

`+

#define V(PropertyName, StringValue) \

`

``

117

`+

tracker->TrackField(#PropertyName, PropertyName(isolate()));

`

``

118

`+

PER_ISOLATE_SYMBOL_PROPERTIES(V)

`

``

119

`+

#undef V

`

``

120

+

``

121

`+

#define V(PropertyName, StringValue) \

`

``

122

`+

tracker->TrackField(#PropertyName, PropertyName(isolate()));

`

``

123

`+

PER_ISOLATE_STRING_PROPERTIES(V)

`

``

124

`+

#undef V

`

``

125

+

``

126

`+

if (node_allocator_ != nullptr) {

`

``

127

`+

tracker->TrackFieldWithSize(

`

``

128

`+

"node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");

`

``

129

`+

} else {

`

``

130

`+

tracker->TrackFieldWithSize(

`

``

131

`+

"allocator", sizeof(*allocator_), "v8::ArrayBuffer::Allocator");

`

``

132

`+

}

`

``

133

`+

tracker->TrackFieldWithSize(

`

``

134

`+

"platform", sizeof(*platform_), "MultiIsolatePlatform");

`

``

135

`+

// TODO(joyeecheung): implement MemoryRetainer in the option classes.

`

``

136

`+

}

`

``

137

+

115

138

`void InitThreadLocalOnce() {

`

116

139

`CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));

`

117

140

`}

`

`@@ -707,6 +730,7 @@ void Environment::set_debug_categories(const std::string& cats, bool enabled) {

`

707

730

` }

`

708

731

``

709

732

`DEBUG_CATEGORY_NAMES(V)

`

``

733

`+

#undef V

`

710

734

``

711

735

`if (comma_pos == std:🧵:npos)

`

712

736

`break;

`

`@@ -775,6 +799,21 @@ void Environment::CollectUVExceptionInfo(Local object,

`

775

799

`syscall, message, path, dest);

`

776

800

`}

`

777

801

``

``

802

`+

void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {

`

``

803

`+

tracker->TrackField("fields", fields_);

`

``

804

`+

}

`

``

805

+

``

806

`+

void TickInfo::MemoryInfo(MemoryTracker* tracker) const {

`

``

807

`+

tracker->TrackField("fields", fields_);

`

``

808

`+

}

`

``

809

+

``

810

`+

void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {

`

``

811

`+

tracker->TrackField("providers", providers_);

`

``

812

`+

tracker->TrackField("async_ids_stack", async_ids_stack_);

`

``

813

`+

tracker->TrackField("fields", fields_);

`

``

814

`+

tracker->TrackField("async_id_fields", async_id_fields_);

`

``

815

`+

}

`

``

816

+

778

817

`void AsyncHooks::grow_async_ids_stack() {

`

779

818

` async_ids_stack_.reserve(async_ids_stack_.Length() * 3);

`

780

819

``

`@@ -805,13 +844,83 @@ void Environment::stop_sub_worker_contexts() {

`

805

844

` }

`

806

845

`}

`

807

846

``

``

847

`+

void MemoryTracker::TrackField(const char* edge_name,

`

``

848

`+

const CleanupHookCallback& value,

`

``

849

`+

const char* node_name) {

`

``

850

`+

v8::HandleScope handle_scope(isolate_);

`

``

851

`+

// Here, we utilize the fact that CleanupHookCallback instances

`

``

852

`+

// are all unique and won't be tracked twice in one BuildEmbedderGraph

`

``

853

`+

// callback.

`

``

854

`+

MemoryRetainerNode* n =

`

``

855

`+

PushNode("CleanupHookCallback", sizeof(value), edge_name);

`

``

856

`+

// TODO(joyeecheung): at the moment only arguments of type BaseObject will be

`

``

857

`+

// identified and tracked here (based on their deleters),

`

``

858

`+

// but we may convert and track other known types here.

`

``

859

`+

BaseObject* obj = value.GetBaseObject();

`

``

860

`+

if (obj != nullptr) {

`

``

861

`+

this->TrackField("arg", obj);

`

``

862

`+

}

`

``

863

`+

CHECK_EQ(CurrentNode(), n);

`

``

864

`+

CHECK_NE(n->size_, 0);

`

``

865

`+

PopNode();

`

``

866

`+

}

`

``

867

+

808

868

`void Environment::BuildEmbedderGraph(Isolate* isolate,

`

809

869

` EmbedderGraph* graph,

`

810

870

`void* data) {

`

811

871

` MemoryTracker tracker(isolate, graph);

`

812

``

`-

static_cast<Environment*>(data)->ForEachBaseObject([&](BaseObject* obj) {

`

813

``

`-

tracker.Track(obj);

`

814

``

`-

});

`

``

872

`+

Environment* env = static_cast<Environment*>(data);

`

``

873

`+

tracker.Track(env);

`

``

874

`+

}

`

``

875

+

``

876

`+

inline size_t Environment::SelfSize() const {

`

``

877

`+

size_t size = sizeof(*this);

`

``

878

`+

// Remove non pointer fields that will be tracked in MemoryInfo()

`

``

879

`+

// TODO(joyeecheung): refactor the MemoryTracker interface so

`

``

880

`+

// this can be done for common types within the Track* calls automatically

`

``

881

`+

// if a certain scope is entered.

`

``

882

`+

size -= sizeof(thread_stopper_);

`

``

883

`+

size -= sizeof(async_hooks_);

`

``

884

`+

size -= sizeof(tick_info_);

`

``

885

`+

size -= sizeof(immediate_info_);

`

``

886

`+

return size;

`

``

887

`+

}

`

``

888

+

``

889

`+

void Environment::MemoryInfo(MemoryTracker* tracker) const {

`

``

890

`+

// Iteratable STLs have their own sizes subtracted from the parent

`

``

891

`+

// by default.

`

``

892

`+

tracker->TrackField("isolate_data", isolate_data_);

`

``

893

`+

tracker->TrackField("native_modules_with_cache", native_modules_with_cache);

`

``

894

`+

tracker->TrackField("native_modules_without_cache",

`

``

895

`+

native_modules_without_cache);

`

``

896

`+

tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);

`

``

897

`+

tracker->TrackField("exec_argv", exec_argv_);

`

``

898

`+

tracker->TrackField("should_abort_on_uncaught_toggle",

`

``

899

`+

should_abort_on_uncaught_toggle_);

`

``

900

`+

tracker->TrackField("stream_base_state", stream_base_state_);

`

``

901

`+

tracker->TrackField("fs_stats_field_array", fs_stats_field_array_);

`

``

902

`+

tracker->TrackField("fs_stats_field_bigint_array",

`

``

903

`+

fs_stats_field_bigint_array_);

`

``

904

`+

tracker->TrackField("thread_stopper", thread_stopper_);

`

``

905

`+

tracker->TrackField("cleanup_hooks", cleanup_hooks_);

`

``

906

`+

tracker->TrackField("async_hooks", async_hooks_);

`

``

907

`+

tracker->TrackField("immediate_info", immediate_info_);

`

``

908

`+

tracker->TrackField("tick_info", tick_info_);

`

``

909

+

``

910

`+

#define V(PropertyName, TypeName) \

`

``

911

`+

tracker->TrackField(#PropertyName, PropertyName());

`

``

912

`+

ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)

`

``

913

`+

#undef V

`

``

914

+

``

915

`+

// FIXME(joyeecheung): track other fields in Environment.

`

``

916

`+

// Currently MemoryTracker is unable to track these

`

``

917

`+

// correctly:

`

``

918

`+

// - Internal types that do not implement MemoryRetainer yet

`

``

919

`+

// - STL containers with MemoryRetainer* inside

`

``

920

`+

// - STL containers with numeric types inside that should not have their

`

``

921

`+

// nodes elided e.g. numeric keys in maps.

`

``

922

`+

// We also need to make sure that when we add a non-pointer field as its own

`

``

923

`+

// node, we shift its sizeof() size out of the Environment node.

`

815

924

`}

`

816

925

``

817

926

`char* Environment::Reallocate(char* data, size_t old_size, size_t size) {

`

`@@ -875,8 +984,4 @@ Local BaseObject::WrappedObject() const {

`

875

984

`return object();

`

876

985

`}

`

877

986

``

878

``

`-

bool BaseObject::IsRootNode() const {

`

879

``

`-

return !persistent_handle_.IsWeak();

`

880

``

`-

}

`

881

``

-

882

987

`} // namespace node

`