Skip to content

Commit 66dacb8

Browse files
chore(memory): sort all by retainer size (#1963)
This is a better measurement as if object self size is X and the retainerSize Y. X will always be smaller then Y, there Y will be the actual size on the Heap.
1 parent 8cbdb8d commit 66dacb8

5 files changed

Lines changed: 113 additions & 106 deletions

File tree

src/McpResponse.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {WebMCPTool} from 'puppeteer-core';
99
import type {ParsedArguments} from './bin/chrome-devtools-mcp-cli-options.js';
1010
import {ConsoleFormatter} from './formatters/ConsoleFormatter.js';
1111
import {HeapSnapshotFormatter} from './formatters/HeapSnapshotFormatter.js';
12+
import {isNodeLike} from './formatters/HeapSnapshotFormatter.js';
1213
import {IssueFormatter} from './formatters/IssueFormatter.js';
1314
import {NetworkFormatter} from './formatters/NetworkFormatter.js';
1415
import {SnapshotFormatter} from './formatters/SnapshotFormatter.js';
@@ -945,8 +946,12 @@ Call ${handleDialog.name} to handle it before continuing.`);
945946
}
946947
const nodes = this.#heapSnapshotOptions.nodes;
947948
if (nodes) {
949+
const sortedItems = nodes.items
950+
.filter(isNodeLike)
951+
.sort((a, b) => b.retainedSize - a.retainedSize);
952+
948953
const paginationData = this.#dataWithPagination(
949-
nodes.items,
954+
sortedItems,
950955
this.#heapSnapshotOptions.pagination,
951956
);
952957

src/formatters/HeapSnapshotFormatter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface FormattedSnapshotEntry {
1616
retainedSize: number;
1717
}
1818

19-
function isNodeLike(
19+
export function isNodeLike(
2020
item: unknown,
2121
): item is DevTools.HeapSnapshotModel.HeapSnapshotModel.Node {
2222
return (
@@ -55,7 +55,7 @@ export class HeapSnapshotFormatter {
5555
}
5656

5757
#getSortedAggregates(): AggregatedInfoWithUid[] {
58-
return Object.values(this.#aggregates).sort((a, b) => b.self - a.self);
58+
return Object.values(this.#aggregates).sort((a, b) => b.maxRet - a.maxRet);
5959
}
6060

6161
toString(): string {
@@ -92,6 +92,6 @@ export class HeapSnapshotFormatter {
9292
): Array<
9393
[string, DevTools.HeapSnapshotModel.HeapSnapshotModel.AggregatedInfo]
9494
> {
95-
return Object.entries(aggregates).sort((a, b) => b[1].self - a[1].self);
95+
return Object.entries(aggregates).sort((a, b) => b[1].maxRet - a[1].maxRet);
9696
}
9797
}

tests/formatters/HeapSnapshotFormatter.test.js.snapshot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
exports[`HeapSnapshotFormatter > toString > formats data as CSV and sorts by self size 1`] = `
1+
exports[`HeapSnapshotFormatter > toString > formats data as CSV and sorts by retained size 1`] = `
22
uid,className,count,selfSize,maxRetainedSize
33
1,"ObjectA",10,100,1000
44
2,"ObjectB",5,50,500

tests/formatters/HeapSnapshotFormatter.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ describe('HeapSnapshotFormatter', () => {
3737
};
3838

3939
describe('toString', () => {
40-
it('formats data as CSV and sorts by self size', t => {
40+
it('formats data as CSV and sorts by retained size', t => {
4141
const formatter = new HeapSnapshotFormatter(mockAggregates);
4242
const result = formatter.toString();
4343
t.assert.snapshot?.(result);
4444
});
4545
});
4646

4747
describe('toJSON', () => {
48-
it('returns structured data sorted by self size', () => {
48+
it('returns structured data sorted by retained size', () => {
4949
const formatter = new HeapSnapshotFormatter(mockAggregates);
5050
const result = formatter.toJSON();
5151
assert.deepStrictEqual(result, [
@@ -68,18 +68,20 @@ describe('HeapSnapshotFormatter', () => {
6868
});
6969

7070
describe('sort', () => {
71-
it('sorts aggregates by self size descending', () => {
71+
it('sorts aggregates by retained size descending', () => {
7272
const unsortedAggregates: Record<
7373
string,
7474
DevTools.HeapSnapshotModel.HeapSnapshotModel.AggregatedInfo
7575
> = {
7676
ObjectB: {
7777
name: 'ObjectB',
7878
self: 50,
79+
maxRet: 500,
7980
},
8081
ObjectA: {
8182
name: 'ObjectA',
8283
self: 100,
84+
maxRet: 1000,
8385
},
8486
} as unknown as Record<
8587
string,

tests/tools/memory.test.js.snapshot

Lines changed: 98 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,158 +3,158 @@ exports[`memory > get_memory_snapshot_details > with default options 1`] = `
33
Showing 1-157 of 157 (Page 1 of 1).
44
uid,className,count,selfSize,maxRetainedSize
55
2,"(system)",3205,199264,655004
6-
16,"(object shape)",2878,181480,184320
76
11,"Function",3581,111464,237120
7+
16,"(object shape)",2878,181480,184320
8+
3,"(array)",34,41416,117472
89
42,"Window (global*) / https://example.com",2,81068,101832
910
94,"Window (prototype) / https://example.com",4,53336,53712
1011
1,"(compiled code)",713,42812,46988
11-
3,"(array)",34,41416,117472
1212
6,"(string)",846,27880,27880
13-
109,"Document",1,8448,8700
14-
105,"HTMLElement",1,4728,4768
15-
104,"Element",1,4224,4540
13+
96,"Window (internal cache) / https://example.com",4,400,20256
1614
15,"Object (global*)",2,3856,13488
17-
10,"HTMLDocument",1,3288,6192
18-
89,"system / Context",116,2544,3488
19-
103,"Node",1,1764,1804
15+
55,"{constructor, toString, toDateString, toTimeString, toISOString, toUTCString, toGMTString, getDate, setDate, getDay}",4,848,8848
2016
49,"TypedArray",48,1424,8784
17+
109,"Document",1,8448,8700
2118
50,"Error",48,1344,7872
22-
106,"HTMLBodyElement (prototype) / https://example.com",1,1188,1228
23-
19,"Array",8,1056,7728
24-
126,"Performance",1,1040,1784
25-
32,"String",4,960,6056
26-
54,"Object",22,928,1168
27-
130,"StyleEngine",1,912,1104
28-
9,"Window / https://example.com",1,904,1944
29-
55,"{constructor, toString, toDateString, toTimeString, toISOString, toUTCString, toGMTString, getDate, setDate, getDay}",4,848,8848
3019
47,"Math",4,816,7792
20+
19,"Array",8,1056,7728
3121
39,"{constructor, buffer, get buffer, byteLength, get byteLength, byteOffset, get byteOffset, length, get length}",4,624,7008
32-
118,"CSSStyleRule",8,576,1024
33-
119,"CSSStyleSheet",3,528,976
22+
10,"HTMLDocument",1,3288,6192
3423
44,"console",4,488,6152
24+
32,"String",4,960,6056
3525
68,"DataView",4,480,5504
26+
105,"HTMLElement",1,4728,4768
27+
62,"Intl.Locale",4,288,4672
28+
104,"Element",1,4224,4540
3629
76,"{constructor, getColumnNumber, getEnclosingColumnNumber, getEnclosingLineNumber, getEvalOrigin, getFileName, getFunction}",4,480,4448
37-
110,"Text",6,480,480
38-
37,"WebAssembly",4,416,1904
39-
96,"Window (internal cache) / https://example.com",4,400,20256
40-
135,"EventListener",10,400,400
41-
40,"{constructor}",14,392,1560
42-
30,"Set",4,384,1616
43-
27,"Map",4,336,1504
44-
43,"Atomics",4,336,3056
4530
45,"Intl",4,336,4192
46-
46,"Reflect",4,336,2480
47-
67,"{at, copyWithin, entries, fill, find, findIndex, findLast, findLastIndex, flat, flatMap, includes, keys, toReversed}",4,336,1344
48-
134,"FontFaceSet",1,328,328
49-
133,"StylePropertyMap",8,320,320
50-
139,"MutationObserver",2,320,320
5131
25,"{<symbol Symbol.iterator>, constructor, get constructor, set constructor, reduce, toArray, forEach, some, every, find}",4,288,3600
52-
28,"{constructor, __defineGetter__, __defineSetter__, hasOwnProperty, __lookupGetter__, __lookupSetter__, isPrototypeOf}",4,288,1128
53-
62,"Intl.Locale",4,288,4672
54-
33,"WeakMap",4,240,960
55-
36,"{constructor, exec, dotAll, get dotAll, flags, get flags, global, get global, hasIndices, get hasIndices, ignoreCase}",4,240,576
56-
48,"Number",4,240,1488
32+
89,"system / Context",116,2544,3488
33+
43,"Atomics",4,336,3056
5734
91,"DisposableStack",4,240,3040
5835
92,"AsyncDisposableStack",4,240,3040
59-
4,"{<symbol handler_function>, <symbol feature_name>}",8,224,352
60-
131,"ScriptedAnimationController",1,208,208
61-
123,"IntersectionObserver",1,200,240
62-
7,"(number)",16,192,192
63-
17,"{isTraceCategoryEnabled, trace, getContinuationPreservedEmbedderData, setContinuationPreservedEmbedderData, console}",4,192,1120
64-
21,"Generator",4,192,1008
65-
23,"AsyncGenerator",4,192,1008
66-
34,"JSON",4,192,1008
67-
35,"Promise",4,192,1000
68-
53,"WeakSet",4,192,416
36+
46,"Reflect",4,336,2480
37+
72,"ArrayBuffer",4,192,2160
38+
9,"Window / https://example.com",1,904,1944
39+
37,"WebAssembly",4,416,1904
40+
58,"{constructor, <symbol Symbol.toStringTag>, resolvedOptions, adoptText, get adoptText, first, get first, next, get next}",4,112,1808
41+
103,"Node",1,1764,1804
42+
126,"Performance",1,1040,1784
43+
30,"Set",4,384,1616
44+
40,"{constructor}",14,392,1560
45+
90,"SharedArrayBuffer",4,112,1552
6946
56,"Intl.NumberFormat",4,192,1536
47+
66,"Intl.DateTimeFormat",4,192,1536
48+
27,"Map",4,336,1504
49+
48,"Number",4,240,1488
50+
70,"Symbol",4,192,1376
51+
67,"{at, copyWithin, entries, fill, find, findIndex, findLast, findLastIndex, flat, flatMap, includes, keys, toReversed}",4,336,1344
52+
106,"HTMLBodyElement (prototype) / https://example.com",1,1188,1228
53+
54,"Object",22,928,1168
7054
59,"Intl.PluralRules",4,192,1168
7155
60,"Intl.RelativeTimeFormat",4,192,1168
7256
61,"Intl.ListFormat",4,192,1168
7357
65,"Intl.DurationFormat",4,192,1168
74-
66,"Intl.DateTimeFormat",4,192,1536
7558
69,"BigInt",4,192,1168
76-
70,"Symbol",4,192,1376
77-
72,"ArrayBuffer",4,192,2160
59+
28,"{constructor, __defineGetter__, __defineSetter__, hasOwnProperty, __lookupGetter__, __lookupSetter__, isPrototypeOf}",4,288,1128
60+
17,"{isTraceCategoryEnabled, trace, getContinuationPreservedEmbedderData, setContinuationPreservedEmbedderData, console}",4,192,1120
61+
130,"StyleEngine",1,912,1104
62+
118,"CSSStyleRule",8,576,1024
63+
21,"Generator",4,192,1008
64+
23,"AsyncGenerator",4,192,1008
65+
34,"JSON",4,192,1008
66+
35,"Promise",4,192,1000
67+
57,"Intl.Collator",4,112,976
68+
119,"CSSStyleSheet",3,528,976
69+
33,"WeakMap",4,240,960
70+
52,"FinalizationRegistry",4,112,928
71+
63,"Intl.DisplayNames",4,112,928
72+
64,"Intl.Segmenter",4,112,928
73+
73,"Async-from-Sync Iterator",4,112,880
74+
22,"{<symbol Symbol.asyncIterator>, <symbol Symbol.asyncDispose>}",4,112,864
75+
85,"{containing, <symbol Symbol.iterator>}",4,112,832
76+
51,"WeakRef",4,112,768
7877
79,"WebAssembly.Table",4,192,768
7978
80,"WebAssembly.Memory",4,192,768
79+
71,"Boolean",4,144,752
80+
18,"Array Iterator",4,112,720
81+
24,"Iterator Helper",4,112,720
82+
26,"Map Iterator",4,112,720
83+
29,"Set Iterator",4,112,720
84+
31,"String Iterator",4,112,720
85+
86,"Segmenter String Iterator",4,112,720
86+
88,"RegExp String Iterator",4,112,720
87+
20,"{constructor, name, message, toString}",4,112,704
88+
87,"{next, return}",4,112,672
89+
75,"AsyncGeneratorFunction",4,112,656
90+
84,"GeneratorFunction",4,112,656
91+
74,"AsyncFunction",4,112,608
92+
81,"WebAssembly.Global",4,112,592
93+
93,"WebAssembly.Suspending",4,112,592
94+
100,"{loadTimes, csi}",2,56,580
95+
36,"{constructor, exec, dotAll, get dotAll, flags, get flags, global, get global, hasIndices, get hasIndices, ignoreCase}",4,240,576
96+
78,"WebAssembly.Instance",4,112,544
97+
83,"WebAssembly.Exception",4,112,544
98+
110,"Text",6,480,480
99+
77,"WebAssembly.Module",4,112,448
100+
82,"WebAssembly.Tag",4,112,448
101+
101,"EventTarget",2,92,436
102+
53,"WeakSet",4,192,416
103+
135,"EventListener",10,400,400
104+
99,"{parse, stringify}",2,40,384
105+
127,"Navigation",1,152,384
106+
4,"{<symbol handler_function>, <symbol feature_name>}",8,224,352
107+
134,"FontFaceSet",1,328,328
108+
133,"StylePropertyMap",8,320,320
109+
139,"MutationObserver",2,320,320
110+
102,"WindowProperties",2,56,280
111+
115,"<style>",1,128,264
112+
123,"IntersectionObserver",1,200,240
113+
132,"MutationObserver::Delegate",2,64,224
114+
131,"ScriptedAnimationController",1,208,208
115+
95,"MutationObserver (prototype) / https://example.com",1,156,196
116+
7,"(number)",16,192,192
80117
120,"NavigationHistoryEntry",1,192,192
81118
129,"StyleSheetCollection",1,192,192
119+
147,"<a>",1,136,192
82120
146,"DocumentTimeline",1,184,184
121+
5,"RegExp",1,100,176
122+
114,"<title>",1,96,176
83123
116,"PerformancePaintTiming",2,176,176
84124
145,"<p>",2,176,176
125+
111,"<div>",1,88,168
85126
122,"ServiceWorkerContainer",1,168,168
86127
125,"Navigator",1,168,168
87128
155,"PerformanceNavigationTiming",1,168,168
88-
95,"MutationObserver (prototype) / https://example.com",1,156,196
89-
127,"Navigation",1,152,384
90-
71,"Boolean",4,144,752
129+
113,"<head>",1,88,152
130+
98,"HTMLDocument (prototype) / https://example.com",1,108,148
91131
117,"PerformanceResourceTiming",1,136,136
92-
147,"<a>",1,136,192
93132
152,"LargestContentfulPaint",1,136,136
94133
38,"Tag",4,128,128
95-
115,"<style>",1,128,264
96134
136,"CustomElementRegistry",1,128,128
97135
138,"CSSRuleList",4,128,128
98136
141,"Storage",2,128,128
99137
13,"<body>",1,112,112
100-
18,"Array Iterator",4,112,720
101-
20,"{constructor, name, message, toString}",4,112,704
102-
22,"{<symbol Symbol.asyncIterator>, <symbol Symbol.asyncDispose>}",4,112,864
103-
24,"Iterator Helper",4,112,720
104-
26,"Map Iterator",4,112,720
105-
29,"Set Iterator",4,112,720
106-
31,"String Iterator",4,112,720
107-
51,"WeakRef",4,112,768
108-
52,"FinalizationRegistry",4,112,928
109-
57,"Intl.Collator",4,112,976
110-
58,"{constructor, <symbol Symbol.toStringTag>, resolvedOptions, adoptText, get adoptText, first, get first, next, get next}",4,112,1808
111-
63,"Intl.DisplayNames",4,112,928
112-
64,"Intl.Segmenter",4,112,928
113-
73,"Async-from-Sync Iterator",4,112,880
114-
74,"AsyncFunction",4,112,608
115-
75,"AsyncGeneratorFunction",4,112,656
116-
77,"WebAssembly.Module",4,112,448
117-
78,"WebAssembly.Instance",4,112,544
118-
81,"WebAssembly.Global",4,112,592
119-
82,"WebAssembly.Tag",4,112,448
120-
83,"WebAssembly.Exception",4,112,544
121-
84,"GeneratorFunction",4,112,656
122-
85,"{containing, <symbol Symbol.iterator>}",4,112,832
123-
86,"Segmenter String Iterator",4,112,720
124-
87,"{next, return}",4,112,672
125-
88,"RegExp String Iterator",4,112,720
126-
90,"SharedArrayBuffer",4,112,1552
127-
93,"WebAssembly.Suspending",4,112,592
138+
14,"Object (global)",2,32,112
128139
121,"DOMTokenList",2,112,112
129-
98,"HTMLDocument (prototype) / https://example.com",1,108,148
130140
148,"HTMLCollection",1,104,104
131141
150,"ScriptRunner",1,104,104
132-
5,"RegExp",1,100,176
133142
112,"<meta>",1,96,96
134-
114,"<title>",1,96,176
135-
101,"EventTarget",2,92,436
136-
111,"<div>",1,88,168
137-
113,"<head>",1,88,152
143+
41,"(concatenated string)",2,40,88
138144
140,"<html>",1,88,88
139145
144,"<h1>",1,88,88
140146
149,"Screen",1,88,88
141147
153,"DocumentType",1,88,88
142148
156,"VisibilityStateEntry",1,88,88
143-
132,"MutationObserver::Delegate",2,64,224
144149
137,"MutationObserverRegistration",1,64,64
145-
100,"{loadTimes, csi}",2,56,580
146-
102,"WindowProperties",2,56,280
150+
8,"Window (global) / https://example.com",1,16,56
147151
151,"FragmentDirective",1,56,56
148-
41,"(concatenated string)",2,40,88
149-
99,"{parse, stringify}",2,40,384
150152
124,"IntersectionObserverDelegate",1,40,40
151153
128,"NavigationActivation",1,40,40
152154
154,"PerformanceTiming",1,40,40
153155
157,"Pending activities",1,40,40
154-
14,"Object (global)",2,32,112
155156
142,"VisualViewport",1,32,32
156157
143,"Viewport",1,32,32
157-
8,"Window (global) / https://example.com",1,16,56
158158
12,"HTMLBodyElement",1,16,16
159159
97,"HTMLDocument (internal cache) / https://example.com",1,16,16
160160
107,"MutationObserver (internal cache) / https://example.com",1,16,16
@@ -165,13 +165,13 @@ exports[`memory > get_nodes_by_class > with default options 1`] = `
165165
## Heap Snapshot Data
166166
id,name,type,distance,selfSize,retainedSize
167167
25307,"Array",object,2,192,2056
168+
46355,"Array",object,2,192,2056
168169
33187,"Array",object,2,192,1664
169170
36255,"Array",object,2,192,1664
170-
45899,"Array",object,5,56,56
171171
45901,"Array",object,5,88,88
172-
46149,"Array",object,5,56,56
173172
46151,"Array",object,5,88,88
174-
46355,"Array",object,2,192,2056
173+
45899,"Array",object,5,56,56
174+
46149,"Array",object,5,56,56
175175
Showing 1-8 of 8 (Page 1 of 1).
176176
`;
177177

0 commit comments

Comments
 (0)