@memlab/core 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -0
- package/dist/index.js +17 -0
- package/dist/lib/Config.d.ts +5 -2
- package/dist/lib/Config.js +9 -2
- package/dist/lib/FileManager.d.ts +2 -0
- package/dist/lib/FileManager.js +1 -0
- package/dist/lib/HeapAnalyzer.d.ts +2 -2
- package/dist/lib/HeapAnalyzer.js +27 -60
- package/dist/lib/InternalValueSetter.d.ts +2 -0
- package/dist/lib/InternalValueSetter.js +2 -0
- package/dist/lib/Types.d.ts +63 -6
- package/dist/lib/Utils.js +24 -1
- package/dist/lib/leak-filters/BaseLeakFilter.rule.d.ts +24 -0
- package/dist/lib/leak-filters/BaseLeakFilter.rule.js +22 -0
- package/dist/lib/leak-filters/LeakFilterRuleList.d.ts +13 -0
- package/dist/lib/leak-filters/LeakFilterRuleList.js +33 -0
- package/dist/lib/leak-filters/LeakObjectFilter.d.ts +19 -0
- package/dist/lib/leak-filters/LeakObjectFilter.js +36 -0
- package/dist/lib/leak-filters/rules/FilterByExternalFilter.rule.d.ts +19 -0
- package/dist/lib/leak-filters/rules/FilterByExternalFilter.rule.js +27 -0
- package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.d.ts +20 -0
- package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.js +40 -0
- package/dist/lib/leak-filters/rules/FilterHermesNode.rule.d.ts +16 -0
- package/dist/lib/leak-filters/rules/FilterHermesNode.rule.js +27 -0
- package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.d.ts +19 -0
- package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.js +27 -0
- package/dist/lib/leak-filters/rules/FilterStackTraceFrame.rule.d.ts +19 -0
- package/dist/lib/leak-filters/rules/FilterStackTraceFrame.rule.js +28 -0
- package/dist/lib/leak-filters/rules/FilterTrivialNode.rule.d.ts +20 -0
- package/dist/lib/leak-filters/rules/FilterTrivialNode.rule.js +33 -0
- package/dist/lib/leak-filters/rules/FilterUnmountedFiberNode.rule.d.ts +20 -0
- package/dist/lib/leak-filters/rules/FilterUnmountedFiberNode.rule.js +37 -0
- package/dist/trace-cluster/TraceBucket.d.ts +1 -0
- package/dist/trace-cluster/TraceBucket.js +12 -1
- package/package.json +2 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FilterOverSizedNodeAsLeakRule = void 0;
|
|
13
|
+
const BaseLeakFilter_rule_1 = require("../BaseLeakFilter.rule");
|
|
14
|
+
/**
|
|
15
|
+
* trivial nodes are not reported as memory leaks
|
|
16
|
+
*/
|
|
17
|
+
class FilterOverSizedNodeAsLeakRule {
|
|
18
|
+
filter(config, node) {
|
|
19
|
+
if (config.oversizeObjectAsLeak) {
|
|
20
|
+
return node.retainedSize > config.oversizeThreshold
|
|
21
|
+
? BaseLeakFilter_rule_1.LeakDecision.LEAK
|
|
22
|
+
: BaseLeakFilter_rule_1.LeakDecision.NOT_LEAK;
|
|
23
|
+
}
|
|
24
|
+
return BaseLeakFilter_rule_1.LeakDecision.MAYBE_LEAK;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.FilterOverSizedNodeAsLeakRule = FilterOverSizedNodeAsLeakRule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { MemLabConfig } from '../../Config';
|
|
11
|
+
import type { IHeapNode } from '../../Types';
|
|
12
|
+
import { ILeakObjectFilterRule, LeakDecision } from '../BaseLeakFilter.rule';
|
|
13
|
+
/**
|
|
14
|
+
* stack trace frames as memory leaks
|
|
15
|
+
*/
|
|
16
|
+
export declare class FilterStackTraceFrameRule implements ILeakObjectFilterRule {
|
|
17
|
+
filter(_config: MemLabConfig, node: IHeapNode): LeakDecision;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=FilterStackTraceFrame.rule.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.FilterStackTraceFrameRule = void 0;
|
|
16
|
+
const BaseLeakFilter_rule_1 = require("../BaseLeakFilter.rule");
|
|
17
|
+
const Utils_1 = __importDefault(require("../../Utils"));
|
|
18
|
+
/**
|
|
19
|
+
* stack trace frames as memory leaks
|
|
20
|
+
*/
|
|
21
|
+
class FilterStackTraceFrameRule {
|
|
22
|
+
filter(_config, node) {
|
|
23
|
+
return Utils_1.default.isStackTraceFrame(node)
|
|
24
|
+
? BaseLeakFilter_rule_1.LeakDecision.LEAK
|
|
25
|
+
: BaseLeakFilter_rule_1.LeakDecision.MAYBE_LEAK;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.FilterStackTraceFrameRule = FilterStackTraceFrameRule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { MemLabConfig } from '../../Config';
|
|
11
|
+
import type { IHeapNode } from '../../Types';
|
|
12
|
+
import { ILeakObjectFilterRule, LeakDecision } from '../BaseLeakFilter.rule';
|
|
13
|
+
/**
|
|
14
|
+
* trivial nodes are not reported as memory leaks
|
|
15
|
+
*/
|
|
16
|
+
export declare class FilterTrivialNodeRule implements ILeakObjectFilterRule {
|
|
17
|
+
filter(config: MemLabConfig, node: IHeapNode): LeakDecision;
|
|
18
|
+
protected isTrivialNode(node: IHeapNode): boolean;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=FilterTrivialNode.rule.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.FilterTrivialNodeRule = void 0;
|
|
16
|
+
const BaseLeakFilter_rule_1 = require("../BaseLeakFilter.rule");
|
|
17
|
+
const Utils_1 = __importDefault(require("../../Utils"));
|
|
18
|
+
/**
|
|
19
|
+
* trivial nodes are not reported as memory leaks
|
|
20
|
+
*/
|
|
21
|
+
class FilterTrivialNodeRule {
|
|
22
|
+
filter(config, node) {
|
|
23
|
+
return this.isTrivialNode(node)
|
|
24
|
+
? BaseLeakFilter_rule_1.LeakDecision.NOT_LEAK
|
|
25
|
+
: BaseLeakFilter_rule_1.LeakDecision.MAYBE_LEAK;
|
|
26
|
+
}
|
|
27
|
+
isTrivialNode(node) {
|
|
28
|
+
return (node.type === 'number' ||
|
|
29
|
+
Utils_1.default.isStringNode(node) ||
|
|
30
|
+
node.type === 'hidden');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.FilterTrivialNodeRule = FilterTrivialNodeRule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { MemLabConfig } from '../../Config';
|
|
11
|
+
import type { IHeapNode } from '../../Types';
|
|
12
|
+
import { ILeakObjectFilterRule, LeakDecision } from '../BaseLeakFilter.rule';
|
|
13
|
+
/**
|
|
14
|
+
* mark React FiberNodes without a React Fiber Root as memory leaks
|
|
15
|
+
*/
|
|
16
|
+
export declare class FilterUnmountedFiberNodeRule implements ILeakObjectFilterRule {
|
|
17
|
+
filter(config: MemLabConfig, node: IHeapNode): LeakDecision;
|
|
18
|
+
protected checkDetachedFiberNode(config: MemLabConfig, node: IHeapNode): boolean;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=FilterUnmountedFiberNode.rule.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.FilterUnmountedFiberNodeRule = void 0;
|
|
16
|
+
const BaseLeakFilter_rule_1 = require("../BaseLeakFilter.rule");
|
|
17
|
+
const Utils_1 = __importDefault(require("../../Utils"));
|
|
18
|
+
/**
|
|
19
|
+
* mark React FiberNodes without a React Fiber Root as memory leaks
|
|
20
|
+
*/
|
|
21
|
+
class FilterUnmountedFiberNodeRule {
|
|
22
|
+
filter(config, node) {
|
|
23
|
+
if (this.checkDetachedFiberNode(config, node)) {
|
|
24
|
+
return BaseLeakFilter_rule_1.LeakDecision.LEAK;
|
|
25
|
+
}
|
|
26
|
+
return BaseLeakFilter_rule_1.LeakDecision.MAYBE_LEAK;
|
|
27
|
+
}
|
|
28
|
+
checkDetachedFiberNode(config, node) {
|
|
29
|
+
if (!config.detectFiberNodeLeak ||
|
|
30
|
+
!Utils_1.default.isFiberNode(node) ||
|
|
31
|
+
Utils_1.default.hasHostRoot(node)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return !Utils_1.default.isNodeDominatedByDeletionsArray(node);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.FilterUnmountedFiberNodeRule = FilterUnmountedFiberNodeRule;
|
|
@@ -25,6 +25,7 @@ export default class NormalizedTrace {
|
|
|
25
25
|
private static diffTraces;
|
|
26
26
|
static diffClusters(newClusters: TraceCluster[], existingClusters: TraceCluster[]): TraceClusterDiff;
|
|
27
27
|
static clusterLeakTraces(leakTraces: LeakTrace[]): Record<string, string>;
|
|
28
|
+
static filterClusters(clusters: TraceCluster[]): TraceCluster[];
|
|
28
29
|
static clusterPaths(paths: LeakTracePathItem[], snapshot: IHeapSnapshot, aggregateDominatorMetrics: AggregateNodeCb, option?: {
|
|
29
30
|
strategy?: IClusterStrategy;
|
|
30
31
|
}): TraceCluster[];
|
|
@@ -171,6 +171,16 @@ class NormalizedTrace {
|
|
|
171
171
|
}, {});
|
|
172
172
|
return labaledLeakTraces;
|
|
173
173
|
}
|
|
174
|
+
static filterClusters(clusters) {
|
|
175
|
+
if (Config_1.default.clusterRetainedSizeThreshold <= 0) {
|
|
176
|
+
return clusters;
|
|
177
|
+
}
|
|
178
|
+
return clusters.filter(cluster => {
|
|
179
|
+
var _a;
|
|
180
|
+
return ((_a = cluster.retainedSize) !== null && _a !== void 0 ? _a : Infinity) >
|
|
181
|
+
Config_1.default.clusterRetainedSizeThreshold;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
174
184
|
static clusterPaths(paths, snapshot, aggregateDominatorMetrics, option = {}) {
|
|
175
185
|
Console_1.default.overwrite('Clustering leak traces');
|
|
176
186
|
if (paths.length === 0) {
|
|
@@ -192,7 +202,7 @@ class NormalizedTrace {
|
|
|
192
202
|
// cluster traces
|
|
193
203
|
const { allClusters } = NormalizedTrace.diffTraces(traces, [], option);
|
|
194
204
|
// construct TraceCluster from clustering result
|
|
195
|
-
|
|
205
|
+
let clusters = allClusters.map((traces) => {
|
|
196
206
|
const cluster = {
|
|
197
207
|
path: traceToPathMap.get(traces[0]),
|
|
198
208
|
count: traces.length,
|
|
@@ -205,6 +215,7 @@ class NormalizedTrace {
|
|
|
205
215
|
this.calculateClusterRetainedSize(cluster, snapshot, aggregateDominatorMetrics);
|
|
206
216
|
return cluster;
|
|
207
217
|
});
|
|
218
|
+
clusters = NormalizedTrace.filterClusters(clusters);
|
|
208
219
|
clusters.sort((c1, c2) => { var _a, _b; return ((_a = c2.retainedSize) !== null && _a !== void 0 ? _a : 0) - ((_b = c1.retainedSize) !== null && _b !== void 0 ? _b : 0); });
|
|
209
220
|
Console_1.default.midLevel(`MemLab found ${clusters.length} leak(s)`);
|
|
210
221
|
return clusters;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "memlab core libraries",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"directory": "packages/core"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
|
+
"preinstall": "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true",
|
|
59
60
|
"build-pkg": "tsc",
|
|
60
61
|
"test-pkg": "jest .",
|
|
61
62
|
"clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
|