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
`