Categorize object shape info in heap snapshots
One of the biggest categories in heap snapshots is named “(system)”, which gives developers no indication of why all that memory is used or what they might do to reduce it. In this change, I propose that we create a new category for Maps, DescriptorArrays, and related objects, and call this new category “(object shape)” in the devtools. I think that this category name would be more meaningful, while still grouping those objects together so that they mostly stay out of the way. Bug: v8:12769 Doc: https://docs.google.com/document/d/1a-6V_2LIJuRcsppwh6E18g8OSnC9j6gN4ao2gq--BiU Change-Id: I282a7b87c34ca6ed371ff32f3c7332d794ae42ca Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3587974 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Cr-Commit-Position: refs/heads/main@{#80123}
This commit is contained in:
parent
370cae1d8f
commit
ee72b7a11f
@ -542,7 +542,9 @@ class V8_EXPORT HeapGraphNode {
|
||||
kConsString = 10, // Concatenated string. A pair of pointers to strings.
|
||||
kSlicedString = 11, // Sliced string. A fragment of another string.
|
||||
kSymbol = 12, // A Symbol (ES6).
|
||||
kBigInt = 13 // BigInt.
|
||||
kBigInt = 13, // BigInt.
|
||||
kObjectShape = 14, // Internal data used for tracking the shapes (or
|
||||
// "hidden classes") of JS objects.
|
||||
};
|
||||
|
||||
/** Returns node type (see HeapGraphNode::Type). */
|
||||
|
@ -380,6 +380,8 @@ const char* HeapEntry::TypeAsString() const {
|
||||
case kSymbol: return "/symbol/";
|
||||
case kBigInt:
|
||||
return "/bigint/";
|
||||
case kObjectShape:
|
||||
return "/object shape/";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
@ -955,6 +957,17 @@ HeapEntry::Type V8HeapExplorer::GetSystemEntryType(HeapObject object) {
|
||||
return HeapEntry::kArray;
|
||||
}
|
||||
|
||||
// Maps in read-only space are for internal V8 data, not user-defined object
|
||||
// shapes.
|
||||
if ((InstanceTypeChecker::IsMap(type) &&
|
||||
!BasicMemoryChunk::FromHeapObject(object)->InReadOnlySpace()) ||
|
||||
InstanceTypeChecker::IsDescriptorArray(type) ||
|
||||
InstanceTypeChecker::IsTransitionArray(type) ||
|
||||
InstanceTypeChecker::IsPrototypeInfo(type) ||
|
||||
InstanceTypeChecker::IsEnumCache(type)) {
|
||||
return HeapEntry::kObjectShape;
|
||||
}
|
||||
|
||||
return HeapEntry::kHidden;
|
||||
}
|
||||
|
||||
@ -1098,6 +1111,8 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) {
|
||||
ExtractFeedbackCellReferences(entry, FeedbackCell::cast(obj));
|
||||
} else if (obj.IsPropertyCell()) {
|
||||
ExtractPropertyCellReferences(entry, PropertyCell::cast(obj));
|
||||
} else if (obj.IsPrototypeInfo()) {
|
||||
ExtractPrototypeInfoReferences(entry, PrototypeInfo::cast(obj));
|
||||
} else if (obj.IsAllocationSite()) {
|
||||
ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
|
||||
} else if (obj.IsArrayBoilerplateDescription()) {
|
||||
@ -1110,6 +1125,10 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) {
|
||||
ExtractFeedbackVectorReferences(entry, FeedbackVector::cast(obj));
|
||||
} else if (obj.IsDescriptorArray()) {
|
||||
ExtractDescriptorArrayReferences(entry, DescriptorArray::cast(obj));
|
||||
} else if (obj.IsEnumCache()) {
|
||||
ExtractEnumCacheReferences(entry, EnumCache::cast(obj));
|
||||
} else if (obj.IsTransitionArray()) {
|
||||
ExtractTransitionArrayReferences(entry, TransitionArray::cast(obj));
|
||||
} else if (obj.IsWeakFixedArray()) {
|
||||
ExtractWeakArrayReferences(WeakFixedArray::kHeaderSize, entry,
|
||||
WeakFixedArray::cast(obj));
|
||||
@ -1412,6 +1431,8 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map map) {
|
||||
TagObject(map.dependent_code(), "(dependent code)");
|
||||
SetInternalReference(entry, "dependent_code", map.dependent_code(),
|
||||
Map::kDependentCodeOffset);
|
||||
TagObject(map.prototype_validity_cell(), "(prototype validity cell)",
|
||||
HeapEntry::kObjectShape);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
|
||||
@ -1556,6 +1577,14 @@ void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
|
||||
PropertyCell::kDependentCodeOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractPrototypeInfoReferences(HeapEntry* entry,
|
||||
PrototypeInfo info) {
|
||||
TagObject(info.prototype_chain_enum_cache(), "(prototype chain enum cache)",
|
||||
HeapEntry::kObjectShape);
|
||||
TagObject(info.prototype_users(), "(prototype users)",
|
||||
HeapEntry::kObjectShape);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
|
||||
AllocationSite site) {
|
||||
SetInternalReference(entry, "transition_info",
|
||||
@ -1723,6 +1752,20 @@ void V8HeapExplorer::ExtractDescriptorArrayReferences(HeapEntry* entry,
|
||||
}
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractEnumCacheReferences(HeapEntry* entry,
|
||||
EnumCache cache) {
|
||||
TagObject(cache.keys(), "(enum cache)", HeapEntry::kObjectShape);
|
||||
TagObject(cache.indices(), "(enum cache)", HeapEntry::kObjectShape);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractTransitionArrayReferences(
|
||||
HeapEntry* entry, TransitionArray transitions) {
|
||||
if (transitions.HasPrototypeTransitions()) {
|
||||
TagObject(transitions.GetPrototypeTransitions(), "(prototype transitions)",
|
||||
HeapEntry::kObjectShape);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
|
||||
HeapEntry* entry, T array) {
|
||||
@ -3015,7 +3058,8 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
|
||||
JSON_S("concatenated string") ","
|
||||
JSON_S("sliced string") ","
|
||||
JSON_S("symbol") ","
|
||||
JSON_S("bigint")) ","
|
||||
JSON_S("bigint") ","
|
||||
JSON_S("object shape")) ","
|
||||
JSON_S("string") ","
|
||||
JSON_S("number") ","
|
||||
JSON_S("number") ","
|
||||
|
@ -118,7 +118,8 @@ class HeapEntry {
|
||||
kConsString = v8::HeapGraphNode::kConsString,
|
||||
kSlicedString = v8::HeapGraphNode::kSlicedString,
|
||||
kSymbol = v8::HeapGraphNode::kSymbol,
|
||||
kBigInt = v8::HeapGraphNode::kBigInt
|
||||
kBigInt = v8::HeapGraphNode::kBigInt,
|
||||
kObjectShape = v8::HeapGraphNode::kObjectShape,
|
||||
};
|
||||
|
||||
HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
|
||||
@ -431,6 +432,7 @@ class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator {
|
||||
void ExtractFeedbackCellReferences(HeapEntry* entry,
|
||||
FeedbackCell feedback_cell);
|
||||
void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell cell);
|
||||
void ExtractPrototypeInfoReferences(HeapEntry* entry, PrototypeInfo info);
|
||||
void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite site);
|
||||
void ExtractArrayBoilerplateDescriptionReferences(
|
||||
HeapEntry* entry, ArrayBoilerplateDescription value);
|
||||
@ -448,6 +450,9 @@ class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator {
|
||||
FeedbackVector feedback_vector);
|
||||
void ExtractDescriptorArrayReferences(HeapEntry* entry,
|
||||
DescriptorArray array);
|
||||
void ExtractEnumCacheReferences(HeapEntry* entry, EnumCache cache);
|
||||
void ExtractTransitionArrayReferences(HeapEntry* entry,
|
||||
TransitionArray transitions);
|
||||
template <typename T>
|
||||
void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T array);
|
||||
void ExtractPropertyReferences(JSObject js_obj, HeapEntry* entry);
|
||||
|
Loading…
Reference in New Issue
Block a user