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:
Seth Brenith 2022-04-15 12:53:32 -07:00 committed by V8 LUCI CQ
parent 370cae1d8f
commit ee72b7a11f
3 changed files with 54 additions and 3 deletions

View File

@ -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). */

View File

@ -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") ","

View File

@ -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);