@memlab/core 1.1.1 → 1.1.2
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/__tests__/parser/HeapParser.test.js +2 -2
- package/dist/__tests__/parser/NodeHeap.test.js +5 -5
- package/dist/__tests__/parser/StringNode.test.js +1 -1
- package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.js +2 -2
- package/dist/lib/Console.d.ts +1 -0
- package/dist/lib/Console.js +3 -0
- package/dist/lib/FileManager.d.ts +2 -0
- package/dist/lib/FileManager.js +6 -0
- package/dist/lib/NodeHeap.d.ts +64 -5
- package/dist/lib/NodeHeap.js +64 -3
- package/dist/lib/Types.d.ts +197 -1
- package/dist/lib/Utils.js +1 -0
- package/package.json +2 -1
|
@@ -36,7 +36,7 @@ test('Capture inserted object', () => __awaiter(void 0, void 0, void 0, function
|
|
|
36
36
|
}
|
|
37
37
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
38
38
|
const injected = new TestObject();
|
|
39
|
-
const heap = yield (0, NodeHeap_1.
|
|
39
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
40
40
|
expect(heap.hasObjectWithClassName('TestObject')).toBe(true);
|
|
41
41
|
}), timeout);
|
|
42
42
|
test('Does not capture transcient object', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -49,6 +49,6 @@ test('Does not capture transcient object', () => __awaiter(void 0, void 0, void
|
|
|
49
49
|
let injected = new TestObject();
|
|
50
50
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
51
|
injected = null;
|
|
52
|
-
const heap = yield (0, NodeHeap_1.
|
|
52
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
53
53
|
expect(heap.hasObjectWithClassName('TestObject')).toBe(false);
|
|
54
54
|
}), timeout);
|
|
@@ -30,7 +30,7 @@ const timeout = 5 * 60 * 1000;
|
|
|
30
30
|
test('Capture current node heap snapshot', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
31
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
32
32
|
const object = { 'memlab-test-heap-property': 'memlab-test-heap-value' };
|
|
33
|
-
const heap = yield (0, NodeHeap_1.
|
|
33
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
34
34
|
expect(heap.hasObjectWithPropertyName('memlab-test-heap-property')).toBe(true);
|
|
35
35
|
}), timeout);
|
|
36
36
|
test('Nullified Object should not exist in heap', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -39,7 +39,7 @@ test('Nullified Object should not exist in heap', () => __awaiter(void 0, void 0
|
|
|
39
39
|
};
|
|
40
40
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
41
41
|
object = null;
|
|
42
|
-
const heap = yield (0, NodeHeap_1.
|
|
42
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
43
43
|
expect(heap.hasObjectWithPropertyName('memlab-test-heap-property')).toBe(false);
|
|
44
44
|
}), timeout);
|
|
45
45
|
test('Strongly referenced object should exist in heap', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -59,7 +59,7 @@ test('Strongly referenced object should exist in heap', () => __awaiter(void 0,
|
|
|
59
59
|
}
|
|
60
60
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
61
61
|
const object = buildTest();
|
|
62
|
-
const heap = yield (0, NodeHeap_1.
|
|
62
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
63
63
|
expect(heap.hasObjectWithClassName('TestClass1')).toBe(true);
|
|
64
64
|
expect(heap.hasObjectWithClassName('TestClass2')).toBe(true);
|
|
65
65
|
}), timeout);
|
|
@@ -80,7 +80,7 @@ test('Weakly referenced object should not exist in heap', () => __awaiter(void 0
|
|
|
80
80
|
}
|
|
81
81
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
82
82
|
const object = buildTest();
|
|
83
|
-
const heap = yield (0, NodeHeap_1.
|
|
83
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
84
84
|
expect(heap.hasObjectWithClassName('TestClass3')).toBe(true);
|
|
85
85
|
expect(heap.hasObjectWithClassName('TestClass4')).toBe(false);
|
|
86
86
|
}), timeout);
|
|
@@ -90,7 +90,7 @@ test('Check annotated objects', () => __awaiter(void 0, void 0, void 0, function
|
|
|
90
90
|
(0, NodeHeap_1.tagObject)(o1, 'memlab-mark-1');
|
|
91
91
|
(0, NodeHeap_1.tagObject)(o2, 'memlab-mark-2');
|
|
92
92
|
o2 = null;
|
|
93
|
-
const heap = yield (0, NodeHeap_1.
|
|
93
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
94
94
|
expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);
|
|
95
95
|
expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
|
|
96
96
|
}), timeout);
|
|
@@ -41,7 +41,7 @@ test('String heap object APIs work', () => __awaiter(void 0, void 0, void 0, fun
|
|
|
41
41
|
injected.complexConcatString += 'value_';
|
|
42
42
|
injected.complexConcatString += 123;
|
|
43
43
|
injected.complexConcatString += '_suffix';
|
|
44
|
-
const heap = yield (0, NodeHeap_1.
|
|
44
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
45
45
|
const testObject = heap.getAnyObjectWithClassName('TestObject');
|
|
46
46
|
expect(testObject).not.toBe(null);
|
|
47
47
|
// testObject.originalString === 'test'
|
|
@@ -74,7 +74,7 @@ test('Check getReference and getReferenceNode', () => __awaiter(void 0, void 0,
|
|
|
74
74
|
});
|
|
75
75
|
return detected;
|
|
76
76
|
};
|
|
77
|
-
const heap = yield (0, NodeHeap_1.
|
|
77
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
78
78
|
expect(checker(heap)).toBe(true);
|
|
79
79
|
}), timeout);
|
|
80
80
|
test('Check getReferrers and getReferrerNodes', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -135,6 +135,6 @@ test('Check getReferrers and getReferrerNodes', () => __awaiter(void 0, void 0,
|
|
|
135
135
|
}
|
|
136
136
|
return true;
|
|
137
137
|
};
|
|
138
|
-
const heap = yield (0, NodeHeap_1.
|
|
138
|
+
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)();
|
|
139
139
|
expect(checker(heap)).toBe(true);
|
|
140
140
|
}), timeout);
|
package/dist/lib/Console.d.ts
CHANGED
package/dist/lib/Console.js
CHANGED
|
@@ -43,6 +43,8 @@ export declare class FileManager {
|
|
|
43
43
|
getAllFilesInDir(dir: string): string[];
|
|
44
44
|
getDataOutDir(options?: FileOption): string;
|
|
45
45
|
getCoreProjectBaseDir(): string;
|
|
46
|
+
getMonoRepoDir(): string;
|
|
47
|
+
getDocDir(): string;
|
|
46
48
|
getReportOutDir(options?: FileOption): string;
|
|
47
49
|
getPreviewReportDir(options?: FileOption): string;
|
|
48
50
|
getLeakSummaryFile(options?: FileOption): string;
|
package/dist/lib/FileManager.js
CHANGED
|
@@ -133,6 +133,12 @@ class FileManager {
|
|
|
133
133
|
getCoreProjectBaseDir() {
|
|
134
134
|
return path_1.default.join(__dirname, '..', '..');
|
|
135
135
|
}
|
|
136
|
+
getMonoRepoDir() {
|
|
137
|
+
return path_1.default.join(this.getCoreProjectBaseDir(), '..', '..');
|
|
138
|
+
}
|
|
139
|
+
getDocDir() {
|
|
140
|
+
return path_1.default.join(this.getMonoRepoDir(), 'website', 'docs');
|
|
141
|
+
}
|
|
136
142
|
getReportOutDir(options = {}) {
|
|
137
143
|
return path_1.default.join(this.getPersistDataDir(options), 'reports');
|
|
138
144
|
}
|
package/dist/lib/NodeHeap.d.ts
CHANGED
|
@@ -7,10 +7,69 @@
|
|
|
7
7
|
* @emails oncall+ws_labs
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import type { IHeapSnapshot } from './Types';
|
|
11
|
+
/**
|
|
12
|
+
* Tags a string marker to an object instance, which can later be checked by
|
|
13
|
+
* {@link hasObjectWithTag}. This API does not modify the object instance in
|
|
14
|
+
* any way (e.g., no additional or hidden properties added to the tagged
|
|
15
|
+
* object).
|
|
16
|
+
*
|
|
17
|
+
* @param o specify the object instance you want to tag, you cannot tag a
|
|
18
|
+
* [primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
19
|
+
* @param tag marker name to tag on the object instance
|
|
20
|
+
* @returns returns the tagged object instance (same reference as
|
|
21
|
+
* the input argument `o`)
|
|
22
|
+
* * **Examples**:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import type {IHeapSnapshot, AnyValue} from '@memlab/core';
|
|
25
|
+
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core';
|
|
26
|
+
*
|
|
27
|
+
* test('memory test', async () => {
|
|
28
|
+
* config.muteConsole = true;
|
|
29
|
+
* const o1: AnyValue = {};
|
|
30
|
+
* let o2: AnyValue = {};
|
|
31
|
+
*
|
|
32
|
+
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way
|
|
33
|
+
* tagObject(o1, 'memlab-mark-1');
|
|
34
|
+
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way
|
|
35
|
+
* tagObject(o2, 'memlab-mark-2');
|
|
36
|
+
*
|
|
37
|
+
* o2 = null;
|
|
38
|
+
*
|
|
39
|
+
* const heap: IHeapSnapshot = await getNodeInnocentHeap();
|
|
40
|
+
*
|
|
41
|
+
* // expect object with marker "memlab-mark-1" exists
|
|
42
|
+
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);
|
|
43
|
+
*
|
|
44
|
+
* // expect object with marker "memlab-mark-2" can be GCed
|
|
45
|
+
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
|
|
46
|
+
*
|
|
47
|
+
* }, 30000);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function tagObject<T extends object>(o: T, tag: string): T;
|
|
13
51
|
export declare function dumpNodeHeapSnapshot(): string;
|
|
14
|
-
|
|
15
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Take a heap snapshot of the current program state
|
|
54
|
+
* and parse it as {@link IHeapSnapshot}. Notice that
|
|
55
|
+
* this API does not calculate some heap analysis meta data
|
|
56
|
+
* for heap analysis. But this also means faster heap parsing.
|
|
57
|
+
*
|
|
58
|
+
* @returns heap representation without heap analysis meta data.
|
|
59
|
+
*
|
|
60
|
+
* If you need to get the heap snapshot with heap analysis meta data
|
|
61
|
+
* use {@link dumpNodeHeapSnapshot} and {@link getHeapFromFile},
|
|
62
|
+
* for example:
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import type {IHeapSnapshot} from '@memlab/core';
|
|
65
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
66
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
67
|
+
*
|
|
68
|
+
* (async function () {
|
|
69
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
70
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
71
|
+
* })();
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function getNodeInnocentHeap(): Promise<IHeapSnapshot>;
|
|
16
75
|
//# sourceMappingURL=NodeHeap.d.ts.map
|
package/dist/lib/NodeHeap.js
CHANGED
|
@@ -21,7 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
24
|
+
exports.getNodeInnocentHeap = exports.dumpNodeHeapSnapshot = exports.tagObject = void 0;
|
|
25
25
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
26
26
|
const path_1 = __importDefault(require("path"));
|
|
27
27
|
const v8_1 = __importDefault(require("v8"));
|
|
@@ -33,6 +33,45 @@ class MemLabTaggedStore {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
const store = new MemLabTaggedStore();
|
|
36
|
+
/**
|
|
37
|
+
* Tags a string marker to an object instance, which can later be checked by
|
|
38
|
+
* {@link hasObjectWithTag}. This API does not modify the object instance in
|
|
39
|
+
* any way (e.g., no additional or hidden properties added to the tagged
|
|
40
|
+
* object).
|
|
41
|
+
*
|
|
42
|
+
* @param o specify the object instance you want to tag, you cannot tag a
|
|
43
|
+
* [primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
44
|
+
* @param tag marker name to tag on the object instance
|
|
45
|
+
* @returns returns the tagged object instance (same reference as
|
|
46
|
+
* the input argument `o`)
|
|
47
|
+
* * **Examples**:
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import type {IHeapSnapshot, AnyValue} from '@memlab/core';
|
|
50
|
+
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core';
|
|
51
|
+
*
|
|
52
|
+
* test('memory test', async () => {
|
|
53
|
+
* config.muteConsole = true;
|
|
54
|
+
* const o1: AnyValue = {};
|
|
55
|
+
* let o2: AnyValue = {};
|
|
56
|
+
*
|
|
57
|
+
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way
|
|
58
|
+
* tagObject(o1, 'memlab-mark-1');
|
|
59
|
+
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way
|
|
60
|
+
* tagObject(o2, 'memlab-mark-2');
|
|
61
|
+
*
|
|
62
|
+
* o2 = null;
|
|
63
|
+
*
|
|
64
|
+
* const heap: IHeapSnapshot = await getNodeInnocentHeap();
|
|
65
|
+
*
|
|
66
|
+
* // expect object with marker "memlab-mark-1" exists
|
|
67
|
+
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);
|
|
68
|
+
*
|
|
69
|
+
* // expect object with marker "memlab-mark-2" can be GCed
|
|
70
|
+
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
|
|
71
|
+
*
|
|
72
|
+
* }, 30000);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
36
75
|
function tagObject(o, tag) {
|
|
37
76
|
if (!store.taggedObjects[tag]) {
|
|
38
77
|
store.taggedObjects[tag] = new WeakSet();
|
|
@@ -47,7 +86,29 @@ function dumpNodeHeapSnapshot() {
|
|
|
47
86
|
return file;
|
|
48
87
|
}
|
|
49
88
|
exports.dumpNodeHeapSnapshot = dumpNodeHeapSnapshot;
|
|
50
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Take a heap snapshot of the current program state
|
|
91
|
+
* and parse it as {@link IHeapSnapshot}. Notice that
|
|
92
|
+
* this API does not calculate some heap analysis meta data
|
|
93
|
+
* for heap analysis. But this also means faster heap parsing.
|
|
94
|
+
*
|
|
95
|
+
* @returns heap representation without heap analysis meta data.
|
|
96
|
+
*
|
|
97
|
+
* If you need to get the heap snapshot with heap analysis meta data
|
|
98
|
+
* use {@link dumpNodeHeapSnapshot} and {@link getHeapFromFile},
|
|
99
|
+
* for example:
|
|
100
|
+
* ```typescript
|
|
101
|
+
* import type {IHeapSnapshot} from '@memlab/core';
|
|
102
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
103
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
104
|
+
*
|
|
105
|
+
* (async function () {
|
|
106
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
107
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
108
|
+
* })();
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
function getNodeInnocentHeap() {
|
|
51
112
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
113
|
const file = dumpNodeHeapSnapshot();
|
|
53
114
|
const snapshot = yield Utils_1.default.getSnapshotFromFile(file, {
|
|
@@ -59,4 +120,4 @@ function getCurrentNodeHeap() {
|
|
|
59
120
|
return snapshot;
|
|
60
121
|
});
|
|
61
122
|
}
|
|
62
|
-
exports.
|
|
123
|
+
exports.getNodeInnocentHeap = getNodeInnocentHeap;
|
package/dist/lib/Types.d.ts
CHANGED
|
@@ -607,15 +607,211 @@ export declare type RunMetaInfo = {
|
|
|
607
607
|
browserInfo: IBrowserInfo;
|
|
608
608
|
};
|
|
609
609
|
export interface IHeapSnapshot {
|
|
610
|
+
/** @internal */
|
|
610
611
|
snapshot: RawHeapSnapshot;
|
|
612
|
+
/**
|
|
613
|
+
* A pseudo array containing all heap graph nodes (JS objects in heap).
|
|
614
|
+
* A JS heap could contain millions of heap objects, so memlab uses
|
|
615
|
+
* a pseudo array as the collection of all the heap objects. The pseudo
|
|
616
|
+
* array provides API to query and traverse all heap objects.
|
|
617
|
+
*
|
|
618
|
+
* * **Examples**:
|
|
619
|
+
* ```typescript
|
|
620
|
+
* import type {IHeapSnapshot, IHeapNode} from '@memlab/core';
|
|
621
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
622
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
623
|
+
*
|
|
624
|
+
* (async function () {
|
|
625
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
626
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
627
|
+
*
|
|
628
|
+
* // get the total number of heap objects
|
|
629
|
+
* heap.nodes.length;
|
|
630
|
+
*
|
|
631
|
+
* heap.nodes.forEach((node: IHeapNode) => {
|
|
632
|
+
* // traverse each heap object
|
|
633
|
+
* });
|
|
634
|
+
* })();
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
611
637
|
nodes: IHeapNodes;
|
|
638
|
+
/**
|
|
639
|
+
* A pseudo array containing all heap graph edges (references to heap objects
|
|
640
|
+
* in heap). A JS heap could contain millions of references, so memlab uses
|
|
641
|
+
* a pseudo array as the collection of all the heap edges. The pseudo
|
|
642
|
+
* array provides API to query and traverse all heap references.
|
|
643
|
+
*
|
|
644
|
+
* * **Examples**:
|
|
645
|
+
* ```typescript
|
|
646
|
+
* import type {IHeapSnapshot, IHeapEdge} from '@memlab/core';
|
|
647
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
648
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
649
|
+
*
|
|
650
|
+
* (async function () {
|
|
651
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
652
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
653
|
+
*
|
|
654
|
+
* // get the total number of heap references
|
|
655
|
+
* heap.edges.length;
|
|
656
|
+
*
|
|
657
|
+
* heap.edges.forEach((edge: IHeapEdge) => {
|
|
658
|
+
* // traverse each reference in the heap
|
|
659
|
+
* });
|
|
660
|
+
* })();
|
|
661
|
+
* ```
|
|
662
|
+
*/
|
|
612
663
|
edges: IHeapEdges;
|
|
664
|
+
/**
|
|
665
|
+
* If you have the id of a heap node (JS object in heap), use this API
|
|
666
|
+
* to get an {@link IHeapNode} associated with the id.
|
|
667
|
+
* @param id id of the heap node (JS object in heap) you would like to query
|
|
668
|
+
* @returns the API returns `null` if no heap object has the specified id.
|
|
669
|
+
*
|
|
670
|
+
* * **Examples**:
|
|
671
|
+
* ```typescript
|
|
672
|
+
* import type {IHeapSnapshot} from '@memlab/core';
|
|
673
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
674
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
675
|
+
*
|
|
676
|
+
* (async function () {
|
|
677
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
678
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
679
|
+
*
|
|
680
|
+
* const node = heap.getNodeById(351);
|
|
681
|
+
* node?.id; // should be 351
|
|
682
|
+
* })();
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
613
685
|
getNodeById(id: number): Nullable<IHeapNode>;
|
|
614
|
-
|
|
686
|
+
/**
|
|
687
|
+
* Search for the heap and check if there is any JS object instance with
|
|
688
|
+
* a specified constructor name.
|
|
689
|
+
* @param className The contructor name of the object instance
|
|
690
|
+
* @returns `true` if there is at least one such object in the heap
|
|
691
|
+
*
|
|
692
|
+
* * **Examples**: you can write a jest unit test with memory assertions:
|
|
693
|
+
* ```typescript
|
|
694
|
+
* // save as example.test.ts
|
|
695
|
+
* import type {IHeapSnapshot, Nullable} from '@memlab/core';
|
|
696
|
+
* import {config, getNodeInnocentHeap} from '@memlab/core';
|
|
697
|
+
*
|
|
698
|
+
* class TestObject {
|
|
699
|
+
* public arr1 = [1, 2, 3];
|
|
700
|
+
* public arr2 = ['1', '2', '3'];
|
|
701
|
+
* }
|
|
702
|
+
*
|
|
703
|
+
* test('memory test with heap assertion', async () => {
|
|
704
|
+
* config.muteConsole = true; // no console output
|
|
705
|
+
*
|
|
706
|
+
* let obj: Nullable<TestObject> = new TestObject();
|
|
707
|
+
* // get a heap snapshot of the current program state
|
|
708
|
+
* let heap: IHeapSnapshot = await getNodeInnocentHeap();
|
|
709
|
+
*
|
|
710
|
+
* // call some function that may add references to obj
|
|
711
|
+
* rabbitHole(obj)
|
|
712
|
+
*
|
|
713
|
+
* expect(heap.hasObjectWithClassName('TestObject')).toBe(true);
|
|
714
|
+
* obj = null;
|
|
715
|
+
*
|
|
716
|
+
* heap = await getNodeInnocentHeap();
|
|
717
|
+
* // if rabbitHole does not have any side effect that
|
|
718
|
+
* // adds new references to obj, then obj can be GCed
|
|
719
|
+
* expect(heap.hasObjectWithClassName('TestObject')).toBe(false);
|
|
720
|
+
*
|
|
721
|
+
* }, 30000);
|
|
722
|
+
* ```
|
|
723
|
+
*/
|
|
615
724
|
hasObjectWithClassName(className: string): boolean;
|
|
725
|
+
/**
|
|
726
|
+
* Search for the heap and get one of the JS object instances with
|
|
727
|
+
* a specified constructor name (if there is any).
|
|
728
|
+
* @param className The contructor name of the object instance
|
|
729
|
+
* @returns a handle pointing to any one of the object instances, returns
|
|
730
|
+
* `null` if no such object exists in the heap.
|
|
731
|
+
*
|
|
732
|
+
* * **Examples**:
|
|
733
|
+
* ```typescript
|
|
734
|
+
* import type {IHeapSnapshot} from '@memlab/core';
|
|
735
|
+
* import {getNodeInnocentHeap} from '@memlab/core';
|
|
736
|
+
*
|
|
737
|
+
* class TestObject {
|
|
738
|
+
* public arr1 = [1, 2, 3];
|
|
739
|
+
* public arr2 = ['1', '2', '3'];
|
|
740
|
+
* }
|
|
741
|
+
*
|
|
742
|
+
* (async function () {
|
|
743
|
+
* const obj = new TestObject();
|
|
744
|
+
* // get a heap snapshot of the current program state
|
|
745
|
+
* const heap: IHeapSnapshot = await getNodeInnocentHeap();
|
|
746
|
+
*
|
|
747
|
+
* const node = heap.getAnyObjectWithClassName('TestObject');
|
|
748
|
+
* console.log(node?.name); // should be 'TestObject'
|
|
749
|
+
* })();
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
616
752
|
getAnyObjectWithClassName(className: string): Nullable<IHeapNode>;
|
|
753
|
+
/**
|
|
754
|
+
* Search for the heap and check if there is any JS object instance with
|
|
755
|
+
* a specified property name.
|
|
756
|
+
* @param nameOrIndex The property name (string) or element index (number)
|
|
757
|
+
* on the object instance
|
|
758
|
+
* @returns returns `true` if there is at least one such object in the heap
|
|
759
|
+
*
|
|
760
|
+
* * **Examples**:
|
|
761
|
+
* ```typescript
|
|
762
|
+
* import type {IHeapSnapshot} from '@memlab/core';
|
|
763
|
+
* import {dumpNodeHeapSnapshot} from '@memlab/core';
|
|
764
|
+
* import {getHeapFromFile} from '@memlab/heap-analysis';
|
|
765
|
+
*
|
|
766
|
+
* (async function () {
|
|
767
|
+
* // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
768
|
+
* const object = {'memlab-test-heap-property': 'memlab-test-heap-value'};
|
|
769
|
+
*
|
|
770
|
+
* const heapFile = dumpNodeHeapSnapshot();
|
|
771
|
+
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile);
|
|
772
|
+
*
|
|
773
|
+
* // should be true
|
|
774
|
+
* console.log(heap.hasObjectWithPropertyName('memlab-test-heap-property'));
|
|
775
|
+
* })();
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
617
778
|
hasObjectWithPropertyName(nameOrIndex: string | number): boolean;
|
|
779
|
+
/**
|
|
780
|
+
* Search for the heap and check if there is any JS object instance with
|
|
781
|
+
* a marker tagged by {@link tagObject}.
|
|
782
|
+
* @param tag marker name on the object instances tagged by {@link tagObject}
|
|
783
|
+
* @returns returns `true` if there is at least one such object in the heap
|
|
784
|
+
*
|
|
785
|
+
* ```typescript
|
|
786
|
+
* import type {IHeapSnapshot, AnyValue} from '@memlab/core';
|
|
787
|
+
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core';
|
|
788
|
+
*
|
|
789
|
+
* test('memory test', async () => {
|
|
790
|
+
* config.muteConsole = true;
|
|
791
|
+
* const o1: AnyValue = {};
|
|
792
|
+
* let o2: AnyValue = {};
|
|
793
|
+
*
|
|
794
|
+
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way
|
|
795
|
+
* tagObject(o1, 'memlab-mark-1');
|
|
796
|
+
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way
|
|
797
|
+
* tagObject(o2, 'memlab-mark-2');
|
|
798
|
+
*
|
|
799
|
+
* o2 = null;
|
|
800
|
+
*
|
|
801
|
+
* const heap: IHeapSnapshot = await getNodeInnocentHeap();
|
|
802
|
+
*
|
|
803
|
+
* // expect object with marker "memlab-mark-1" exists
|
|
804
|
+
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);
|
|
805
|
+
*
|
|
806
|
+
* // expect object with marker "memlab-mark-2" can be GCed
|
|
807
|
+
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
|
|
808
|
+
*
|
|
809
|
+
* }, 30000);
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
618
812
|
hasObjectWithTag(tag: string): boolean;
|
|
813
|
+
/** @internal */
|
|
814
|
+
clearShortestPathInfo(): void;
|
|
619
815
|
}
|
|
620
816
|
export interface IHeapLocation {
|
|
621
817
|
snapshot: IHeapSnapshot;
|
package/dist/lib/Utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "memlab core libraries",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build-pkg": "tsc",
|
|
60
60
|
"test-pkg": "jest .",
|
|
61
|
+
"publish-patch": "npm version patch --force && npm publish",
|
|
61
62
|
"clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
|
|
62
63
|
},
|
|
63
64
|
"bugs": {
|