From 0f11b29f81d558bb81e5050e68c4a475f6d0978c Mon Sep 17 00:00:00 2001 From: Liang Gong Date: Wed, 1 May 2024 13:02:17 -0700 Subject: [PATCH] Prevent external retainer trace edge filter from OOMing memlab path finder (#117) Summary: External leak filter's `retainerReferenceFilter` callback could return `true` for edges that shouldn't be used. For example, self-referencing edges cause to infinite loop when traversing from a node to the GC root. MemLab's default edge filter excludes these kind of edges, but MemLab's path finder didn't consider the case where external leak filter may bypass MemLab's internal edge filter. This diff makes a patch to MemLab so that its path finder will consider the case where external edge filter includes edges that should be bypassed. Differential Revision: D56803842 fbshipit-source-id: d25ab366c5a1562927d284299a0bcfb057d9330a --- packages/core/src/lib/Types.ts | 16 ++++- packages/core/src/lib/Utils.ts | 5 +- packages/core/src/paths/TraceFinder.ts | 8 ++- .../api/interfaces/core_src.IBrowserInfo.md | 6 +- .../docs/api/interfaces/core_src.IHeapEdge.md | 18 ++--- .../api/interfaces/core_src.IHeapEdges.md | 6 +- .../api/interfaces/core_src.IHeapLocation.md | 12 ++-- .../docs/api/interfaces/core_src.IHeapNode.md | 64 +++++++++--------- .../api/interfaces/core_src.IHeapNodes.md | 6 +- .../api/interfaces/core_src.IHeapSnapshot.md | 18 ++--- .../interfaces/core_src.IHeapStringNode.md | 66 +++++++++---------- .../api/interfaces/core_src.ILeakFilter.md | 10 ++- .../docs/api/interfaces/core_src.IScenario.md | 22 +++---- website/docs/api/modules/core_src.md | 22 ++++--- 14 files changed, 156 insertions(+), 123 deletions(-) diff --git a/packages/core/src/lib/Types.ts b/packages/core/src/lib/Types.ts index b40c16a6..cc03aa6d 100644 --- a/packages/core/src/lib/Types.ts +++ b/packages/core/src/lib/Types.ts @@ -509,11 +509,17 @@ export interface ILeakFilter { * therefore, the reference and heap object will not be included in the * retainer trace detection and retainer size calculation. * + * Please also be aware that some edges like self-referencing edges, + * JS engine's internal edges, and hidden edges should not be considered + * as part of the retainer trace. These edges could make the retainer trace + * unncessarily complex and cause confusion. `isReferenceUsedByDefault` will + * be `false` for these types of edges. + * * * **Examples**: * ```javascript * // save as leak-filter.js * module.exports = { - * retainerReferenceFilter(edge, _snapshot, _leakedNodeIds) { + * retainerReferenceFilter(edge, _snapshot, _isReferenceUsedByDefault) { * // exclude react fiber references * if (edge.name_or_index.toString().startsWith('__reactFiber$')) { * return false; @@ -596,10 +602,16 @@ export type LeakFilterCallback = ( * @returns the value indicating whether the given reference should be * filtered (i.e., included) * + * Please also be aware that some edges like self-referencing edges, + * JS engine's internal edges, and hidden edges should not be considered + * as part of the retainer trace. These edges could make the retainer trace + * unncessarily complex and cause confusion. `isReferenceUsedByDefault` will + * be `false` for these types of edges. + * * * **Examples**: * ```javascript * // exclude react fiber references - * function retainerReferenceFilter(edge, _snapshot, _leakedNodeIds) { + * function retainerReferenceFilter(edge, _snapshot, _isReferenceUsedByDefault) { * if (edge.name_or_index.toString().startsWith('__reactFiber$')) { * return false; * } diff --git a/packages/core/src/lib/Utils.ts b/packages/core/src/lib/Utils.ts index 67abaf45..a2d3fa33 100644 --- a/packages/core/src/lib/Utils.ts +++ b/packages/core/src/lib/Utils.ts @@ -686,7 +686,10 @@ function loadLeakFilter(filename: string): ILeakFilter { if (typeof filter === 'function') { return {leakFilter: filter}; } - if (typeof filter?.leakFilter === 'function') { + if ( + typeof filter?.leakFilter === 'function' || + typeof filter?.retainerReferenceFilter === 'function' + ) { return filter; } throw haltOrThrow(`Invalid leak filter in ${filepath}`); diff --git a/packages/core/src/paths/TraceFinder.ts b/packages/core/src/paths/TraceFinder.ts index 6f186266..f9c371f0 100644 --- a/packages/core/src/paths/TraceFinder.ts +++ b/packages/core/src/paths/TraceFinder.ts @@ -727,10 +727,16 @@ class TraceFinder { if (!node || !node.hasPathEdge) { return null; } + const visited = new Set([node.id]); let path: LeakTracePathItem = {node}; while (node && node.hasPathEdge) { const edge: IHeapEdge = node.pathEdge as IHeapEdge; - path = {node: edge.fromNode, edge, next: path}; + const fromNode = edge.fromNode; + if (visited.has(fromNode.id)) { + return null; + } + visited.add(fromNode.id); + path = {node: fromNode, edge, next: path}; node = edge.fromNode; } return path; diff --git a/website/docs/api/interfaces/core_src.IBrowserInfo.md b/website/docs/api/interfaces/core_src.IBrowserInfo.md index ab6d435e..6e9dd9d2 100644 --- a/website/docs/api/interfaces/core_src.IBrowserInfo.md +++ b/website/docs/api/interfaces/core_src.IBrowserInfo.md @@ -16,7 +16,7 @@ through [RunMetaInfo](../modules/core_src.md#runmetainfo). browser version * **Source**: - * core/src/lib/Types.ts:1220 + * core/src/lib/Types.ts:1232 ___ @@ -25,7 +25,7 @@ ___ all web console output * **Source**: - * core/src/lib/Types.ts:1228 + * core/src/lib/Types.ts:1240 ___ @@ -34,4 +34,4 @@ ___ configuration for puppeteer * **Source**: - * core/src/lib/Types.ts:1224 + * core/src/lib/Types.ts:1236 diff --git a/website/docs/api/interfaces/core_src.IHeapEdge.md b/website/docs/api/interfaces/core_src.IHeapEdge.md index d0cfa626..c4f7ab84 100644 --- a/website/docs/api/interfaces/core_src.IHeapEdge.md +++ b/website/docs/api/interfaces/core_src.IHeapEdge.md @@ -45,7 +45,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; index of this JS reference inside the `edge.snapshot.edges` pseudo array * **Source**: - * core/src/lib/Types.ts:1648 + * core/src/lib/Types.ts:1660 ___ @@ -55,7 +55,7 @@ returns an [IHeapNode](core_src.IHeapNode.md) instance representing the hosting JS heap object where this reference starts * **Source**: - * core/src/lib/Types.ts:1669 + * core/src/lib/Types.ts:1681 ___ @@ -67,7 +67,7 @@ otherwise this is a reference with a string name (`edge.name_or_index` will return a string) * **Source**: - * core/src/lib/Types.ts:1655 + * core/src/lib/Types.ts:1667 ___ @@ -77,7 +77,7 @@ name of the JS reference. If this is a reference to an array element or internal table element, it is an numeric index * **Source**: - * core/src/lib/Types.ts:1604 + * core/src/lib/Types.ts:1616 ___ @@ -86,7 +86,7 @@ ___ get the [IHeapSnapshot](core_src.IHeapSnapshot.md) containing this JS reference * **Source**: - * core/src/lib/Types.ts:1644 + * core/src/lib/Types.ts:1656 ___ @@ -96,7 +96,7 @@ returns an [IHeapNode](core_src.IHeapNode.md) instance representing the JS heap pointed to by this reference * **Source**: - * core/src/lib/Types.ts:1664 + * core/src/lib/Types.ts:1676 ___ @@ -105,7 +105,7 @@ ___ the index of the JS heap object pointed to by this reference * **Source**: - * core/src/lib/Types.ts:1659 + * core/src/lib/Types.ts:1671 ___ @@ -115,7 +115,7 @@ type of the JS reference, all types: `context`, `element`, `property`, `internal`, `hidden`, `shortcut`, `weak` * **Source**: - * core/src/lib/Types.ts:1609 + * core/src/lib/Types.ts:1621 ## Methods @@ -136,4 +136,4 @@ captured by the hosting object. * `...args`: `any`[] * **Returns**: `string` * **Source**: - * core/src/lib/Types.ts:1682 + * core/src/lib/Types.ts:1694 diff --git a/website/docs/api/interfaces/core_src.IHeapEdges.md b/website/docs/api/interfaces/core_src.IHeapEdges.md index 6a1164c5..0562d05f 100644 --- a/website/docs/api/interfaces/core_src.IHeapEdges.md +++ b/website/docs/api/interfaces/core_src.IHeapEdges.md @@ -41,7 +41,7 @@ The total number of edges in heap graph (or JS references in heap snapshot). * **Source**: - * core/src/lib/Types.ts:1719 + * core/src/lib/Types.ts:1731 ## Methods @@ -54,7 +54,7 @@ to each element in ascending order of element index. * `callback`: (`edge`: [`IHeapEdge`](core_src.IHeapEdge.md), `index`: `number`) => `boolean` \| `void` | the callback does not need to return any value, if the callback returns `false` when iterating on element at index `i`, then all elements after `i` won't be iterated. * **Returns**: `void` * **Source**: - * core/src/lib/Types.ts:1735 + * core/src/lib/Types.ts:1747 ___ @@ -68,4 +68,4 @@ get an [IHeapEdge](core_src.IHeapEdge.md) element at the specified index at the specified index, otherwise it returns `null`. * **Source**: - * core/src/lib/Types.ts:1727 + * core/src/lib/Types.ts:1739 diff --git a/website/docs/api/interfaces/core_src.IHeapLocation.md b/website/docs/api/interfaces/core_src.IHeapLocation.md index a137cc60..709fd2c5 100644 --- a/website/docs/api/interfaces/core_src.IHeapLocation.md +++ b/website/docs/api/interfaces/core_src.IHeapLocation.md @@ -43,7 +43,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; get the column number * **Source**: - * core/src/lib/Types.ts:1582 + * core/src/lib/Types.ts:1594 ___ @@ -52,7 +52,7 @@ ___ get the line number * **Source**: - * core/src/lib/Types.ts:1578 + * core/src/lib/Types.ts:1590 ___ @@ -61,7 +61,7 @@ ___ get the heap object this location this location represents * **Source**: - * core/src/lib/Types.ts:1570 + * core/src/lib/Types.ts:1582 ___ @@ -70,7 +70,7 @@ ___ get the script ID of the source file * **Source**: - * core/src/lib/Types.ts:1574 + * core/src/lib/Types.ts:1586 ___ @@ -79,7 +79,7 @@ ___ get the [IHeapSnapshot](core_src.IHeapSnapshot.md) containing this location instance * **Source**: - * core/src/lib/Types.ts:1566 + * core/src/lib/Types.ts:1578 ## Methods @@ -100,4 +100,4 @@ captured by the hosting object. * `...args`: `any`[] * **Returns**: `string` * **Source**: - * core/src/lib/Types.ts:1595 + * core/src/lib/Types.ts:1607 diff --git a/website/docs/api/interfaces/core_src.IHeapNode.md b/website/docs/api/interfaces/core_src.IHeapNode.md index 9211c81b..78cda5c9 100644 --- a/website/docs/api/interfaces/core_src.IHeapNode.md +++ b/website/docs/api/interfaces/core_src.IHeapNode.md @@ -52,7 +52,7 @@ For more information on what a dominator node is, please check out [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#dominators). * **Source**: - * core/src/lib/Types.ts:1876 + * core/src/lib/Types.ts:1888 ___ @@ -62,7 +62,7 @@ The total number of outgoing JS references (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1830 + * core/src/lib/Types.ts:1842 ___ @@ -72,7 +72,7 @@ returns true if the heap node has been set an incoming edge which leads to the parent node on the shortest path to GC root. * **Source**: - * core/src/lib/Types.ts:1852 + * core/src/lib/Types.ts:1864 ___ @@ -81,7 +81,7 @@ ___ unique id of the heap object * **Source**: - * core/src/lib/Types.ts:1757 + * core/src/lib/Types.ts:1769 ___ @@ -91,7 +91,7 @@ check if this a string node (normal string node, concatenated string node or sliced string node) * **Source**: - * core/src/lib/Types.ts:1888 + * core/src/lib/Types.ts:1900 ___ @@ -104,7 +104,7 @@ from the React Fiber tree, `is_detached` will be `true`; otherwise it will be `false` * **Source**: - * core/src/lib/Types.ts:1812 + * core/src/lib/Types.ts:1824 ___ @@ -114,7 +114,7 @@ source location information of this heap object (if it is recorded by the heap snapshot). * **Source**: - * core/src/lib/Types.ts:1881 + * core/src/lib/Types.ts:1893 ___ @@ -125,7 +125,7 @@ for JS object instances (type `object`), `name` is the constructor's name of the object instance. for `string`, `name` is the string value. * **Source**: - * core/src/lib/Types.ts:1753 + * core/src/lib/Types.ts:1765 ___ @@ -134,7 +134,7 @@ ___ index of this heap object inside the `node.snapshot.nodes` pseudo array * **Source**: - * core/src/lib/Types.ts:1861 + * core/src/lib/Types.ts:1873 ___ @@ -144,7 +144,7 @@ Get the number of all incoming references pointing to this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1847 + * core/src/lib/Types.ts:1859 ___ @@ -154,7 +154,7 @@ The incoming edge which leads to the parent node on the shortest path to GC root. * **Source**: - * core/src/lib/Types.ts:1857 + * core/src/lib/Types.ts:1869 ___ @@ -164,7 +164,7 @@ Get a JS array containing all outgoing JS references from this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1837 + * core/src/lib/Types.ts:1849 ___ @@ -174,7 +174,7 @@ Get a JS array containing all incoming JS references pointing to this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1842 + * core/src/lib/Types.ts:1854 ___ @@ -186,7 +186,7 @@ could be released if this object is released). For difference between [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#object_sizes). * **Source**: - * core/src/lib/Types.ts:1868 + * core/src/lib/Types.ts:1880 ___ @@ -198,7 +198,7 @@ by the object itself.). For difference between **shallow size** and [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#object_sizes). * **Source**: - * core/src/lib/Types.ts:1825 + * core/src/lib/Types.ts:1837 ___ @@ -207,7 +207,7 @@ ___ get the [IHeapSnapshot](core_src.IHeapSnapshot.md) containing this heap object * **Source**: - * core/src/lib/Types.ts:1804 + * core/src/lib/Types.ts:1816 ___ @@ -220,7 +220,7 @@ This is engine-specific, for example all types in V8: `symbol`, `bigint` * **Source**: - * core/src/lib/Types.ts:1747 + * core/src/lib/Types.ts:1759 ## Methods @@ -244,7 +244,7 @@ const reference = node.findAnyReference((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1960 + * core/src/lib/Types.ts:1972 ___ @@ -268,7 +268,7 @@ const referrer = node.findAnyReferrer((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1977 + * core/src/lib/Types.ts:1989 ___ @@ -293,7 +293,7 @@ const referrer = node.findAnyReferrerNode((node: IHeapNode) => { ``` * **Source**: - * core/src/lib/Types.ts:1995 + * core/src/lib/Types.ts:2007 ___ @@ -318,7 +318,7 @@ const referrerNodes = node.findReferrerNodes((node: IHeapNode) => { ``` * **Source**: - * core/src/lib/Types.ts:2030 + * core/src/lib/Types.ts:2042 ___ @@ -342,7 +342,7 @@ const referrers = node.findReferrers((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:2012 + * core/src/lib/Types.ts:2024 ___ @@ -367,7 +367,7 @@ node.forEachReference((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1925 + * core/src/lib/Types.ts:1937 ___ @@ -392,7 +392,7 @@ node.forEachReferrer((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1943 + * core/src/lib/Types.ts:1955 ___ @@ -413,7 +413,7 @@ const reference = node.getAnyReferrer('ref', 'property'); ``` * **Source**: - * core/src/lib/Types.ts:2085 + * core/src/lib/Types.ts:2097 ___ @@ -439,7 +439,7 @@ const n2 = node.getAnyReferrer('ref', 'property')?.fromNode; ``` * **Source**: - * core/src/lib/Types.ts:2108 + * core/src/lib/Types.ts:2120 ___ @@ -460,7 +460,7 @@ const reference = node.getReference('map', 'hidden'); ``` * **Source**: - * core/src/lib/Types.ts:2045 + * core/src/lib/Types.ts:2057 ___ @@ -485,7 +485,7 @@ const hiddenClassNode2 = node.getReference('map', 'hidden')?.toNode; ``` * **Source**: - * core/src/lib/Types.ts:2067 + * core/src/lib/Types.ts:2079 ___ @@ -512,7 +512,7 @@ const nodes2 = node.getReferrers('ref', 'property') ``` * **Source**: - * core/src/lib/Types.ts:2148 + * core/src/lib/Types.ts:2160 ___ @@ -534,7 +534,7 @@ const referrers = node.getReferrers('ref', 'property'); ``` * **Source**: - * core/src/lib/Types.ts:2127 + * core/src/lib/Types.ts:2139 ___ @@ -555,7 +555,7 @@ captured by the hosting object. * `...args`: `any`[] * **Returns**: `string` * **Source**: - * core/src/lib/Types.ts:1907 + * core/src/lib/Types.ts:1919 ___ @@ -567,4 +567,4 @@ inside the string node. * **Returns**: [`Nullable`](../modules/core_src.md#nullable)<[`IHeapStringNode`](core_src.IHeapStringNode.md)\> * **Source**: - * core/src/lib/Types.ts:1894 + * core/src/lib/Types.ts:1906 diff --git a/website/docs/api/interfaces/core_src.IHeapNodes.md b/website/docs/api/interfaces/core_src.IHeapNodes.md index 94b71359..8722bef9 100644 --- a/website/docs/api/interfaces/core_src.IHeapNodes.md +++ b/website/docs/api/interfaces/core_src.IHeapNodes.md @@ -41,7 +41,7 @@ The total number of nodes in heap graph (or JS objects in heap snapshot). * **Source**: - * core/src/lib/Types.ts:2226 + * core/src/lib/Types.ts:2238 ## Methods @@ -54,7 +54,7 @@ to each element in ascending order of element index. * `callback`: (`node`: [`IHeapNode`](core_src.IHeapNode.md), `index`: `number`) => `boolean` \| `void` | the callback does not need to return any value, if the callback returns `false` when iterating on element at index `i`, then all elements after `i` won't be iterated. * **Returns**: `void` * **Source**: - * core/src/lib/Types.ts:2242 + * core/src/lib/Types.ts:2254 ___ @@ -68,4 +68,4 @@ get an [IHeapNode](core_src.IHeapNode.md) element at the specified index at the specified index, otherwise it returns `null`. * **Source**: - * core/src/lib/Types.ts:2234 + * core/src/lib/Types.ts:2246 diff --git a/website/docs/api/interfaces/core_src.IHeapSnapshot.md b/website/docs/api/interfaces/core_src.IHeapSnapshot.md index b613634e..ae261fcf 100644 --- a/website/docs/api/interfaces/core_src.IHeapSnapshot.md +++ b/website/docs/api/interfaces/core_src.IHeapSnapshot.md @@ -39,7 +39,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1320 + * core/src/lib/Types.ts:1332 ___ @@ -70,7 +70,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1294 + * core/src/lib/Types.ts:1306 ## Methods @@ -105,7 +105,7 @@ class TestObject { ``` * **Source**: - * core/src/lib/Types.ts:1461 + * core/src/lib/Types.ts:1473 ___ @@ -134,7 +134,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1342 + * core/src/lib/Types.ts:1354 ___ @@ -166,7 +166,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1394 + * core/src/lib/Types.ts:1406 ___ @@ -198,7 +198,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1368 + * core/src/lib/Types.ts:1380 ___ @@ -244,7 +244,7 @@ test('memory test with heap assertion', async () => { ``` * **Source**: - * core/src/lib/Types.ts:1433 + * core/src/lib/Types.ts:1445 ___ @@ -276,7 +276,7 @@ import {getFullHeapFromFile} from '@memlab/heap-analysis'; ``` * **Source**: - * core/src/lib/Types.ts:1487 + * core/src/lib/Types.ts:1499 ___ @@ -320,4 +320,4 @@ test('memory test', async () => { ``` * **Source**: - * core/src/lib/Types.ts:1525 + * core/src/lib/Types.ts:1537 diff --git a/website/docs/api/interfaces/core_src.IHeapStringNode.md b/website/docs/api/interfaces/core_src.IHeapStringNode.md index aaa35ce0..1252a02f 100644 --- a/website/docs/api/interfaces/core_src.IHeapStringNode.md +++ b/website/docs/api/interfaces/core_src.IHeapStringNode.md @@ -51,7 +51,7 @@ For more information on what a dominator node is, please check out [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#dominators). * **Source**: - * core/src/lib/Types.ts:1876 + * core/src/lib/Types.ts:1888 ___ @@ -61,7 +61,7 @@ The total number of outgoing JS references (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1830 + * core/src/lib/Types.ts:1842 ___ @@ -71,7 +71,7 @@ returns true if the heap node has been set an incoming edge which leads to the parent node on the shortest path to GC root. * **Source**: - * core/src/lib/Types.ts:1852 + * core/src/lib/Types.ts:1864 ___ @@ -80,7 +80,7 @@ ___ unique id of the heap object * **Source**: - * core/src/lib/Types.ts:1757 + * core/src/lib/Types.ts:1769 ___ @@ -90,7 +90,7 @@ check if this a string node (normal string node, concatenated string node or sliced string node) * **Source**: - * core/src/lib/Types.ts:1888 + * core/src/lib/Types.ts:1900 ___ @@ -103,7 +103,7 @@ from the React Fiber tree, `is_detached` will be `true`; otherwise it will be `false` * **Source**: - * core/src/lib/Types.ts:1812 + * core/src/lib/Types.ts:1824 ___ @@ -113,7 +113,7 @@ source location information of this heap object (if it is recorded by the heap snapshot). * **Source**: - * core/src/lib/Types.ts:1881 + * core/src/lib/Types.ts:1893 ___ @@ -124,7 +124,7 @@ for JS object instances (type `object`), `name` is the constructor's name of the object instance. for `string`, `name` is the string value. * **Source**: - * core/src/lib/Types.ts:1753 + * core/src/lib/Types.ts:1765 ___ @@ -133,7 +133,7 @@ ___ index of this heap object inside the `node.snapshot.nodes` pseudo array * **Source**: - * core/src/lib/Types.ts:1861 + * core/src/lib/Types.ts:1873 ___ @@ -143,7 +143,7 @@ Get the number of all incoming references pointing to this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1847 + * core/src/lib/Types.ts:1859 ___ @@ -153,7 +153,7 @@ The incoming edge which leads to the parent node on the shortest path to GC root. * **Source**: - * core/src/lib/Types.ts:1857 + * core/src/lib/Types.ts:1869 ___ @@ -163,7 +163,7 @@ Get a JS array containing all outgoing JS references from this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1837 + * core/src/lib/Types.ts:1849 ___ @@ -173,7 +173,7 @@ Get a JS array containing all incoming JS references pointing to this heap object (including engine-internal, native, and JS references). * **Source**: - * core/src/lib/Types.ts:1842 + * core/src/lib/Types.ts:1854 ___ @@ -185,7 +185,7 @@ could be released if this object is released). For difference between [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#object_sizes). * **Source**: - * core/src/lib/Types.ts:1868 + * core/src/lib/Types.ts:1880 ___ @@ -197,7 +197,7 @@ by the object itself.). For difference between **shallow size** and [this doc](https://developer.chrome.com/docs/devtools/memory-problems/memory-101/#object_sizes). * **Source**: - * core/src/lib/Types.ts:1825 + * core/src/lib/Types.ts:1837 ___ @@ -206,7 +206,7 @@ ___ get the [IHeapSnapshot](core_src.IHeapSnapshot.md) containing this heap object * **Source**: - * core/src/lib/Types.ts:1804 + * core/src/lib/Types.ts:1816 ___ @@ -216,7 +216,7 @@ get the string value of the JS string heap object associated with this `IHeapStringNode` instance in heap * **Source**: - * core/src/lib/Types.ts:2189 + * core/src/lib/Types.ts:2201 ___ @@ -229,7 +229,7 @@ This is engine-specific, for example all types in V8: `symbol`, `bigint` * **Source**: - * core/src/lib/Types.ts:1747 + * core/src/lib/Types.ts:1759 ## Methods @@ -253,7 +253,7 @@ const reference = node.findAnyReference((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1960 + * core/src/lib/Types.ts:1972 ___ @@ -277,7 +277,7 @@ const referrer = node.findAnyReferrer((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1977 + * core/src/lib/Types.ts:1989 ___ @@ -302,7 +302,7 @@ const referrer = node.findAnyReferrerNode((node: IHeapNode) => { ``` * **Source**: - * core/src/lib/Types.ts:1995 + * core/src/lib/Types.ts:2007 ___ @@ -327,7 +327,7 @@ const referrerNodes = node.findReferrerNodes((node: IHeapNode) => { ``` * **Source**: - * core/src/lib/Types.ts:2030 + * core/src/lib/Types.ts:2042 ___ @@ -351,7 +351,7 @@ const referrers = node.findReferrers((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:2012 + * core/src/lib/Types.ts:2024 ___ @@ -376,7 +376,7 @@ node.forEachReference((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1925 + * core/src/lib/Types.ts:1937 ___ @@ -401,7 +401,7 @@ node.forEachReferrer((edge: IHeapEdge) => { ``` * **Source**: - * core/src/lib/Types.ts:1943 + * core/src/lib/Types.ts:1955 ___ @@ -422,7 +422,7 @@ const reference = node.getAnyReferrer('ref', 'property'); ``` * **Source**: - * core/src/lib/Types.ts:2085 + * core/src/lib/Types.ts:2097 ___ @@ -448,7 +448,7 @@ const n2 = node.getAnyReferrer('ref', 'property')?.fromNode; ``` * **Source**: - * core/src/lib/Types.ts:2108 + * core/src/lib/Types.ts:2120 ___ @@ -469,7 +469,7 @@ const reference = node.getReference('map', 'hidden'); ``` * **Source**: - * core/src/lib/Types.ts:2045 + * core/src/lib/Types.ts:2057 ___ @@ -494,7 +494,7 @@ const hiddenClassNode2 = node.getReference('map', 'hidden')?.toNode; ``` * **Source**: - * core/src/lib/Types.ts:2067 + * core/src/lib/Types.ts:2079 ___ @@ -521,7 +521,7 @@ const nodes2 = node.getReferrers('ref', 'property') ``` * **Source**: - * core/src/lib/Types.ts:2148 + * core/src/lib/Types.ts:2160 ___ @@ -543,7 +543,7 @@ const referrers = node.getReferrers('ref', 'property'); ``` * **Source**: - * core/src/lib/Types.ts:2127 + * core/src/lib/Types.ts:2139 ___ @@ -564,7 +564,7 @@ captured by the hosting object. * `...args`: `any`[] * **Returns**: `string` * **Source**: - * core/src/lib/Types.ts:1907 + * core/src/lib/Types.ts:1919 ___ @@ -576,4 +576,4 @@ inside the string node. * **Returns**: [`Nullable`](../modules/core_src.md#nullable)<[`IHeapStringNode`](core_src.IHeapStringNode.md)\> * **Source**: - * core/src/lib/Types.ts:1894 + * core/src/lib/Types.ts:1906 diff --git a/website/docs/api/interfaces/core_src.ILeakFilter.md b/website/docs/api/interfaces/core_src.ILeakFilter.md index ba189324..627c8f97 100644 --- a/website/docs/api/interfaces/core_src.ILeakFilter.md +++ b/website/docs/api/interfaces/core_src.ILeakFilter.md @@ -186,11 +186,17 @@ the object will be considered as unreachable in the heap graph; and therefore, the reference and heap object will not be included in the retainer trace detection and retainer size calculation. +Please also be aware that some edges like self-referencing edges, +JS engine's internal edges, and hidden edges should not be considered +as part of the retainer trace. These edges could make the retainer trace +unncessarily complex and cause confusion. `isReferenceUsedByDefault` will +be `false` for these types of edges. + * **Examples**: ```javascript // save as leak-filter.js module.exports = { - retainerReferenceFilter(edge, _snapshot, _leakedNodeIds) { + retainerReferenceFilter(edge, _snapshot, _isReferenceUsedByDefault) { // exclude react fiber references if (edge.name_or_index.toString().startsWith('__reactFiber$')) { return false; @@ -212,4 +218,4 @@ memlab run --scenario --leak-filter ``` * **Source**: - * core/src/lib/Types.ts:537 + * core/src/lib/Types.ts:543 diff --git a/website/docs/api/interfaces/core_src.IScenario.md b/website/docs/api/interfaces/core_src.IScenario.md index 6e2a97e8..049d9951 100644 --- a/website/docs/api/interfaces/core_src.IScenario.md +++ b/website/docs/api/interfaces/core_src.IScenario.md @@ -90,7 +90,7 @@ module.exports = scenario; ``` * **Source**: - * core/src/lib/Types.ts:829 + * core/src/lib/Types.ts:841 ___ @@ -121,7 +121,7 @@ Check out [this page](/docs/how-memlab-works) on why memlab needs to undo/revert the `action` callback. * **Source**: - * core/src/lib/Types.ts:855 + * core/src/lib/Types.ts:867 ___ @@ -156,7 +156,7 @@ module.exports = scenario; ``` * **Source**: - * core/src/lib/Types.ts:733 + * core/src/lib/Types.ts:745 ___ @@ -189,7 +189,7 @@ module.exports = { ``` * **Source**: - * core/src/lib/Types.ts:941 + * core/src/lib/Types.ts:953 ___ @@ -233,7 +233,7 @@ module.exports = { ``` * **Source**: - * core/src/lib/Types.ts:913 + * core/src/lib/Types.ts:925 ___ @@ -283,7 +283,7 @@ module.exports = { ``` * **Source**: - * core/src/lib/Types.ts:986 + * core/src/lib/Types.ts:998 ___ @@ -334,7 +334,7 @@ module.exports = { ``` * **Source**: - * core/src/lib/Types.ts:1032 + * core/src/lib/Types.ts:1044 ___ @@ -370,7 +370,7 @@ module.exports = scenario; ``` * **Source**: - * core/src/lib/Types.ts:782 + * core/src/lib/Types.ts:794 ## Methods @@ -405,7 +405,7 @@ module.exports = scenario; ``` * **Source**: - * core/src/lib/Types.ts:703 + * core/src/lib/Types.ts:715 ___ @@ -430,7 +430,7 @@ module.exports = { * **Returns**: `number` * **Source**: - * core/src/lib/Types.ts:874 + * core/src/lib/Types.ts:886 ___ @@ -453,4 +453,4 @@ load. All objects allocated by the initial page load will be candidates for memory leak filtering. * **Source**: - * core/src/lib/Types.ts:751 + * core/src/lib/Types.ts:763 diff --git a/website/docs/api/modules/core_src.md b/website/docs/api/modules/core_src.md index 7d7a258e..75c7d924 100644 --- a/website/docs/api/modules/core_src.md +++ b/website/docs/api/modules/core_src.md @@ -34,7 +34,7 @@ this callback until it returns `true`. This is an async callback, you can also `await` and returns `true` until some async logic is resolved. * **Source**: - * core/src/lib/Types.ts:1154 + * core/src/lib/Types.ts:1166 ___ @@ -86,7 +86,7 @@ or [forEachReferrer](../interfaces/core_src.IHeapNode.md#foreachreferrer). * **Returns**: [`Optional`](core_src.md#optional)<{ `stop`: `boolean` }\> \| `void` | this API returns void * **Source**: - * core/src/lib/Types.ts:1767 + * core/src/lib/Types.ts:1779 ___ @@ -102,7 +102,7 @@ For concrete example, check out [beforeLeakFilter](../interfaces/core_src.ILeakF * **Returns**: `void` * **Source**: - * core/src/lib/Types.ts:548 + * core/src/lib/Types.ts:554 ___ @@ -118,7 +118,7 @@ For concrete examples, check out [action](../interfaces/core_src.IScenario.md#ac * **Returns**: `Promise`<`void`\> | no return value * **Source**: - * core/src/lib/Types.ts:628 + * core/src/lib/Types.ts:640 ___ @@ -146,7 +146,7 @@ function leakFilter(node, _snapshot, _leakedNodeIds) { ``` * **Source**: - * core/src/lib/Types.ts:575 + * core/src/lib/Types.ts:581 ___ @@ -274,10 +274,16 @@ For concrete examples, check out [leakFilter](../interfaces/core_src.ILeakFilter * **Returns**: `boolean` | the value indicating whether the given reference should be filtered (i.e., included) +Please also be aware that some edges like self-referencing edges, +JS engine's internal edges, and hidden edges should not be considered +as part of the retainer trace. These edges could make the retainer trace +unncessarily complex and cause confusion. `isReferenceUsedByDefault` will +be `false` for these types of edges. + * **Examples**: ```javascript // exclude react fiber references -function retainerReferenceFilter(edge, _snapshot, _leakedNodeIds) { +function retainerReferenceFilter(edge, _snapshot, _isReferenceUsedByDefault) { if (edge.name_or_index.toString().startsWith('__reactFiber$')) { return false; } @@ -288,7 +294,7 @@ function retainerReferenceFilter(edge, _snapshot, _leakedNodeIds) { ``` * **Source**: - * core/src/lib/Types.ts:612 + * core/src/lib/Types.ts:624 ___ @@ -303,7 +309,7 @@ You can retrieve the instance of this type through [getRunMetaInfo](../classes/a | `type` | `string` | type of the memlab run | * **Source**: - * core/src/lib/Types.ts:1235 + * core/src/lib/Types.ts:1247 ___