meminsight-test-demo 1.0.0
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/LICENSE +201 -0
- package/README.md +36 -0
- package/docs/Build.md +68 -0
- package/docs/Interface.md +35 -0
- package/docs/UserGuide.md +332 -0
- package/docs/resources/analyzer.png +0 -0
- package/docs/resources/cfg_filter_filetype_json.png +0 -0
- package/docs/resources/filetype_txt.png +0 -0
- package/docs/resources/framework.png +0 -0
- package/docs/resources/output.png +0 -0
- package/docs/resources/process.png +0 -0
- package/package.json +54 -0
- package/packages/cfg/ArkStatCfg.json +33 -0
- package/packages/core/jest.config.js +8 -0
- package/packages/core/package.json +61 -0
- package/packages/core/src/Index.ts +53 -0
- package/packages/core/src/analyzer/AnalysisInfo.ts +298 -0
- package/packages/core/src/analyzer/ArkAnalyzer.ts +42 -0
- package/packages/core/src/analyzer/ArkCmpCfg.ts +22 -0
- package/packages/core/src/analyzer/ArkCompareAnalyzer.ts +173 -0
- package/packages/core/src/analyzer/ArkLeakAnalyzer.ts +196 -0
- package/packages/core/src/analyzer/ArkSerializer.ts +163 -0
- package/packages/core/src/analyzer/ArkStatAnalyzer.ts +191 -0
- package/packages/core/src/analyzer/ArkStatCfg.ts +77 -0
- package/packages/core/src/analyzer/ArkTracePath.ts +269 -0
- package/packages/core/src/analyzer/ArkTracer.ts +42 -0
- package/packages/core/src/analyzer/ArkXAnalyzer.ts +631 -0
- package/packages/core/src/analyzer/IAnalyzer.ts +27 -0
- package/packages/core/src/file/FileReader.ts +82 -0
- package/packages/core/src/file/FileService.ts +50 -0
- package/packages/core/src/file/FileWriter.ts +148 -0
- package/packages/core/src/report/Reporter.ts +81 -0
- package/packages/core/src/report/templates/template.ejs +101 -0
- package/packages/core/src/report/templates/template.ts +103 -0
- package/packages/core/src/shell/DeviceShell.ts +179 -0
- package/packages/core/src/shell/Shell.ts +99 -0
- package/packages/core/src/types/Constants.ts +16 -0
- package/packages/core/src/types/LeakTypes.ts +21 -0
- package/packages/core/src/types/OhosTypes.ts +115 -0
- package/packages/core/src/utils/Common.ts +37 -0
- package/packages/core/src/utils/Finder.ts +390 -0
- package/packages/core/src/utils/Loader.ts +53 -0
- package/packages/core/src/utils/Log.ts +252 -0
- package/packages/core/src/utils/Output.ts +271 -0
- package/packages/core/tsconfig.json +10 -0
- package/packages/exampletools/package.json +52 -0
- package/packages/exampletools/src/MemTest.ts +64 -0
- package/packages/exampletools/tsconfig.json +15 -0
- package/packages/meminsight/jest.config.js +8 -0
- package/packages/meminsight/package.json +52 -0
- package/packages/meminsight/src/Index.ts +4 -0
- package/packages/meminsight/src/Version.ts +7 -0
- package/packages/meminsight/src/process/ArkCompareProc.ts +160 -0
- package/packages/meminsight/src/process/ArkGCProc.ts +61 -0
- package/packages/meminsight/src/process/ArkLeakProc.ts +47 -0
- package/packages/meminsight/src/process/ArkStatProc.ts +320 -0
- package/packages/meminsight/src/process/ArkXProc.ts +73 -0
- package/packages/meminsight/src/process/HMemXProc.ts +50 -0
- package/packages/meminsight/src/process/IProcess.ts +12 -0
- package/packages/meminsight/tsconfig.json +15 -0
- package/packages/stack/README.md +31 -0
- package/packages/stack/libs/hstack_lib-1.0.0.tgz +0 -0
- package/packages/stack/libs/hstack_lib-1.0.1.tgz +0 -0
- package/packages/stack/libs/hstack_lib-1.0.4.tgz +0 -0
- package/packages/stack/libs/lib_list.json +34 -0
- package/packages/stack/package.json +27 -0
- package/packages/stack/src/Index.js +29 -0
- package/packages/stack/src/StackTracer.js +53 -0
- package/packages/templates/ArkLeaks.template +9 -0
- package/packages/templates/ArkNodes.template +9 -0
- package/packages/templates/ArkPaths.template +9 -0
- package/test/scripts/merge.py +145 -0
- package/test/scripts/stat.py +175 -0
- package/test/test_ark_stat_proc.sh +14 -0
- package/tsconfig.base.json +38 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IHeapSnapshot,
|
|
3
|
+
IHeapNode,
|
|
4
|
+
IHeapEdge,
|
|
5
|
+
Nullable,
|
|
6
|
+
TraceFinder,
|
|
7
|
+
LeakTracePathItem
|
|
8
|
+
} from "@memlab/core";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 查找器
|
|
12
|
+
*/
|
|
13
|
+
export class Finder {
|
|
14
|
+
private static traceFinder: TraceFinder = new TraceFinder();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 判断是否是指定名称属性的边
|
|
18
|
+
* @param edge 边
|
|
19
|
+
* @param propName 名称
|
|
20
|
+
* @returns true/false
|
|
21
|
+
*/
|
|
22
|
+
public static isPropEdgeWithName(edge: IHeapEdge, propName: string) : boolean {
|
|
23
|
+
return edge.type === 'property' && edge.name_or_index === propName;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 判断是否是Proto属性的边
|
|
28
|
+
* @param edge 边
|
|
29
|
+
* @returns true/false
|
|
30
|
+
*/
|
|
31
|
+
public static isProtoPropEdge(edge: IHeapEdge) {
|
|
32
|
+
return edge.type === 'property' && edge.name_or_index === 'Proto';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 判断是否是hclass属性的边
|
|
37
|
+
* @param edge 边
|
|
38
|
+
* @returns true/false
|
|
39
|
+
*/
|
|
40
|
+
public static isHClassPropEdge(edge: IHeapEdge) {
|
|
41
|
+
return edge.type === 'property' && edge.name_or_index === 'hclass';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 共享内存类型
|
|
46
|
+
* 例举关键类型
|
|
47
|
+
*/
|
|
48
|
+
public static OOM_SHARED_TYPES: string[] = [
|
|
49
|
+
'js_shared_object',
|
|
50
|
+
'js_shared_array',
|
|
51
|
+
'js_shared_map',
|
|
52
|
+
'js_shared_set'
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
public static STRING_UNIQUE_ID = 'shared_heap_string_unique_id_0123456789';
|
|
56
|
+
|
|
57
|
+
public static isSharedHeapNode(node: IHeapNode) : boolean {
|
|
58
|
+
// String 类对象属于 shared heap
|
|
59
|
+
if (node.isString) {
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
// 共享内存类型与节点名称匹配的
|
|
63
|
+
if (Finder.OOM_SHARED_TYPES.includes(node.name)) {
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
// 先判断 Proto
|
|
67
|
+
let protoEdge = node.findAnyReference((edge: IHeapEdge) => { return Finder.isProtoPropEdge(edge) })
|
|
68
|
+
if (protoEdge) {
|
|
69
|
+
// 通过 proto 查找是否是 shared heap
|
|
70
|
+
if (this.OOM_SHARED_TYPES.includes(protoEdge.toNode.name)) {
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
return this.isSharedHeapNode(protoEdge.toNode)
|
|
74
|
+
}
|
|
75
|
+
// 再判断 hclass
|
|
76
|
+
let hclassEdge = node.findAnyReference((edge: IHeapEdge) => { return this.isHClassPropEdge(edge) })
|
|
77
|
+
if (hclassEdge === null) {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
return this.isSharedHeapNode(hclassEdge.toNode)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public static getSharedHeapNodesMap(snapshot: IHeapSnapshot) : Map<string, Array<IHeapNode>> {
|
|
84
|
+
let nodesMap = new Map<string, Array<IHeapNode>>();
|
|
85
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
86
|
+
if (Finder.isSharedHeapNode(node)) {
|
|
87
|
+
let tag = node.isString ? Finder.STRING_UNIQUE_ID : node.name;
|
|
88
|
+
let nodes = nodesMap.get(tag);
|
|
89
|
+
if (nodes === undefined) {
|
|
90
|
+
nodes = new Array<IHeapNode>();
|
|
91
|
+
}
|
|
92
|
+
nodes.push(node);
|
|
93
|
+
nodesMap.set(tag, nodes);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return nodesMap;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 获取所有shared heap节点的retained size大小总和
|
|
101
|
+
* @param snapshot heapsnapshot
|
|
102
|
+
*/
|
|
103
|
+
public static getSharedHeapNodeRetainedSize(snapshot: IHeapSnapshot) : number {
|
|
104
|
+
let retained_size = 0;
|
|
105
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
106
|
+
if (Finder.isSharedHeapNode(node)) {
|
|
107
|
+
retained_size += node.retainedSize;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return retained_size;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 获取所有string类型对象的retained size大小总和
|
|
115
|
+
* @param snapshot heapsnapshot
|
|
116
|
+
* @returns retained size of shared heap string
|
|
117
|
+
*/
|
|
118
|
+
public static getStringRetainedSize(snapshot: IHeapSnapshot) : number {
|
|
119
|
+
let retained_size = 0;
|
|
120
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
121
|
+
if (node.isString) {
|
|
122
|
+
retained_size += node.retainedSize;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return retained_size;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public static isSharedHeapNodeId(snapshot: IHeapSnapshot, nodeId: number) : boolean {
|
|
129
|
+
const node = snapshot.getNodeById(nodeId)
|
|
130
|
+
if (node === null) {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
return Finder.isSharedHeapNode(node)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 是否是GCRoot节点
|
|
138
|
+
* @param node 目标节点
|
|
139
|
+
* @returns true/false
|
|
140
|
+
*/
|
|
141
|
+
public static isGCRoot(targetNode: IHeapNode): boolean {
|
|
142
|
+
return targetNode.numOfReferrers === 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 是否是Distance为1的节点
|
|
147
|
+
* @param targetNode 目标节点
|
|
148
|
+
* @returns true/false
|
|
149
|
+
*/
|
|
150
|
+
public static isEqualDistanceOne(targetNode: IHeapNode): boolean {
|
|
151
|
+
let result = false;
|
|
152
|
+
targetNode.pathEdge
|
|
153
|
+
targetNode.referrers.forEach((referrer: IHeapEdge) => {
|
|
154
|
+
if (referrer.fromNode.numOfReferrers === 0) {
|
|
155
|
+
result = true;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 查找指定ID的节点
|
|
163
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
164
|
+
* @param nodeId 节点ID
|
|
165
|
+
* @returns
|
|
166
|
+
*/
|
|
167
|
+
public static findNodeById(snapshot: IHeapSnapshot, nodeId: number) : Nullable<IHeapNode> {
|
|
168
|
+
return snapshot.getNodeById(nodeId);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 查找满足过滤条件的节点
|
|
173
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
174
|
+
* @param filter 过滤器
|
|
175
|
+
* @returns IHeapNode Array
|
|
176
|
+
*/
|
|
177
|
+
public static findNodesByFilter(snapshot: IHeapSnapshot, filter: (node: IHeapNode) => boolean) : Array<IHeapNode> {
|
|
178
|
+
const result = new Array<IHeapNode>();
|
|
179
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
180
|
+
if (filter(node)) {
|
|
181
|
+
result.push(node);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 按过滤器和过滤条件查找节点
|
|
189
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
190
|
+
* @param filter 过滤器
|
|
191
|
+
* @param condition 过滤条件
|
|
192
|
+
* @returns IHeapNode Array
|
|
193
|
+
*/
|
|
194
|
+
public static findNodesByFilterCondition(snapshot: IHeapSnapshot,
|
|
195
|
+
filter: (node: IHeapNode, condition: any) => boolean, condition: any) : Array<IHeapNode> {
|
|
196
|
+
const result = new Array<IHeapNode>();
|
|
197
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
198
|
+
if (filter(node, condition)) {
|
|
199
|
+
result.push(node);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 查找所有GCRoot节点
|
|
207
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
208
|
+
* @returns IHeapNode Array
|
|
209
|
+
*/
|
|
210
|
+
public static findGCRoots(snapshot: IHeapSnapshot) : Array<IHeapNode> {
|
|
211
|
+
let filter = (node: IHeapNode) => Finder.isGCRoot(node);
|
|
212
|
+
return Finder.findNodesByFilter(snapshot, filter);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* 查找Detached节点
|
|
217
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
218
|
+
* @returns IHeapNode Array
|
|
219
|
+
*/
|
|
220
|
+
public static findDetachedNodes(snapshot: IHeapSnapshot) : Array<IHeapNode> {
|
|
221
|
+
let filter = (node: IHeapNode) => node.is_detached;
|
|
222
|
+
return Finder.findNodesByFilter(snapshot, filter);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 查找指定个数的Detached节点
|
|
227
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
228
|
+
* @param nodeName 节点名称
|
|
229
|
+
* @returns IHeapNode Array
|
|
230
|
+
*/
|
|
231
|
+
public static findDetachedNodesByName(snapshot: IHeapSnapshot, nodeName: string) : Array<IHeapNode> {
|
|
232
|
+
const result = new Array<IHeapNode>();
|
|
233
|
+
snapshot.nodes.forEach((node: IHeapNode, ) => {
|
|
234
|
+
if (node.is_detached && node.name === nodeName) {
|
|
235
|
+
result.push(node);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* find nodes by distance from gc root
|
|
243
|
+
* @param snapshot snapshot
|
|
244
|
+
* @param distance distance <= 1
|
|
245
|
+
* @returns Array<IHeapNode>
|
|
246
|
+
*/
|
|
247
|
+
public static findNodesByDistanceOne(snapshot: IHeapSnapshot, includeGCRoot: boolean = false) : Array<IHeapNode> {
|
|
248
|
+
let filter = (node: IHeapNode) => {
|
|
249
|
+
return (includeGCRoot && Finder.isGCRoot(node)) || Finder.isEqualDistanceOne(node);
|
|
250
|
+
};
|
|
251
|
+
return Finder.findNodesByFilter(snapshot, filter);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 查找指定节点名称的节点
|
|
256
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
257
|
+
* @param nodeName 节点名称
|
|
258
|
+
* @returns IHeapNode Array
|
|
259
|
+
*/
|
|
260
|
+
public static findNodesByName(snapshot: IHeapSnapshot, nodeName: string) : Array<IHeapNode> {
|
|
261
|
+
let filter = (node: IHeapNode) => {
|
|
262
|
+
return node.name == nodeName;
|
|
263
|
+
};
|
|
264
|
+
return Finder.findNodesByFilter(snapshot, filter);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 查找指定节点名称的节点,最大个数为
|
|
269
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
270
|
+
* @param nodeName 节点名称
|
|
271
|
+
* @param count 查找对象个数(按节点id号排序)
|
|
272
|
+
* @param reverse 是否倒序查找
|
|
273
|
+
* @returns IHeapNode Array
|
|
274
|
+
*/
|
|
275
|
+
public static findNodesByNameCount(
|
|
276
|
+
snapshot: IHeapSnapshot,
|
|
277
|
+
nodeName: string,
|
|
278
|
+
count: number) : Array<IHeapNode> {
|
|
279
|
+
const result = new Array<IHeapNode>();
|
|
280
|
+
let nodeCount = 0;
|
|
281
|
+
snapshot.nodes.forEach((node, )=> {
|
|
282
|
+
if((node.name == nodeName) && (nodeCount < count)) {
|
|
283
|
+
result.push(node);
|
|
284
|
+
nodeCount += 1;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
*
|
|
292
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
293
|
+
* @param nodeName 节点名称
|
|
294
|
+
* @returns
|
|
295
|
+
*/
|
|
296
|
+
public static findNodesByNameDistanceOne(snapshot: IHeapSnapshot, nodeName: string, includeGCRoot: boolean = false) : Array<IHeapNode> {
|
|
297
|
+
let filter = (node: IHeapNode) => {
|
|
298
|
+
return (node.name === nodeName)
|
|
299
|
+
&& ((includeGCRoot && Finder.isGCRoot(node)) || Finder.isEqualDistanceOne(node));
|
|
300
|
+
};
|
|
301
|
+
return Finder.findNodesByFilter(snapshot, filter);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 查找指定节点的最短引用路径
|
|
306
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
307
|
+
* @param targetNode 节点对象
|
|
308
|
+
* @returns 引用链路径
|
|
309
|
+
*/
|
|
310
|
+
public static findShortestPathToGCRoot(snapshot: IHeapSnapshot, targetNode: IHeapNode): LeakTracePathItem | undefined {
|
|
311
|
+
Finder.traceFinder.annotateShortestPaths(snapshot); // 标记最短路径
|
|
312
|
+
const optPath = Finder.traceFinder.getPathToGCRoots(snapshot, targetNode);
|
|
313
|
+
return optPath ? optPath : undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 查找指定节点数组的所有最短引用路径
|
|
318
|
+
* @param snapshot 快照对象 IHeapSnapshot
|
|
319
|
+
* @param targetNodes 节点对象数组
|
|
320
|
+
* @returns 引用链路径数组
|
|
321
|
+
*/
|
|
322
|
+
public static findShortestPaths(snapshot: IHeapSnapshot, targetNodes: IHeapNode[]): Array<LeakTracePathItem> {
|
|
323
|
+
const result: Array<LeakTracePathItem> = new Array<LeakTracePathItem>();
|
|
324
|
+
Finder.traceFinder.annotateShortestPaths(snapshot);
|
|
325
|
+
targetNodes.forEach(node => {
|
|
326
|
+
const optPath = Finder.traceFinder.getPathToGCRoots(snapshot, node);
|
|
327
|
+
if (optPath) {
|
|
328
|
+
result.push(optPath);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* 获取堆节点的最短路径
|
|
336
|
+
* @param node 堆节点
|
|
337
|
+
* @returns 最短路径的节点名称数组
|
|
338
|
+
* @example
|
|
339
|
+
*/
|
|
340
|
+
public static getShortestPath(node: IHeapNode): [number[], string[], number] {
|
|
341
|
+
const shortestPathNodeIds: number[] = []
|
|
342
|
+
const shortestPathStrings: string[] = []
|
|
343
|
+
let distance = 0;
|
|
344
|
+
let shortestPathNode = node
|
|
345
|
+
while (shortestPathNode && shortestPathNode.hasPathEdge) {
|
|
346
|
+
let edge = shortestPathNode.pathEdge
|
|
347
|
+
if (edge) {
|
|
348
|
+
distance++;
|
|
349
|
+
shortestPathNodeIds.push(edge.fromNode.id);
|
|
350
|
+
shortestPathStrings.push(edge.fromNode.name);
|
|
351
|
+
shortestPathNode = edge.fromNode
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return [shortestPathNodeIds, shortestPathStrings, distance];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 获取节点模块名(兼容5.x & 6.0)
|
|
359
|
+
* @param name 节点名称
|
|
360
|
+
* @returns module name
|
|
361
|
+
*/
|
|
362
|
+
public static getModuleName(name: string): string {
|
|
363
|
+
let nameSplit = name.split('#');
|
|
364
|
+
if (nameSplit.length > 1) {
|
|
365
|
+
// 6.0
|
|
366
|
+
return nameSplit[0];
|
|
367
|
+
}
|
|
368
|
+
// 5.x
|
|
369
|
+
return name.split(' ')[0];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* 获取节点Class名(兼容5.x & 6.0)
|
|
374
|
+
* @param name 节点名称
|
|
375
|
+
* @returns class name
|
|
376
|
+
*/
|
|
377
|
+
public static getClassName(name: string): string {
|
|
378
|
+
let regex = /^(.*?)\(line:\d+\).*?$/;
|
|
379
|
+
const match = regex.exec(name);
|
|
380
|
+
if (match) {
|
|
381
|
+
return match[1];
|
|
382
|
+
}
|
|
383
|
+
let regex5 = /^(.*?)\(.*?\)$/;
|
|
384
|
+
const match5 = regex5.exec(name);
|
|
385
|
+
if (match5) {
|
|
386
|
+
return match5[1]
|
|
387
|
+
}
|
|
388
|
+
return name;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { IHeapSnapshot, utils, AnyOptions } from "@memlab/core";
|
|
2
|
+
import { getFullHeapFromFile } from "@memlab/heap-analysis";
|
|
3
|
+
import { Log } from "../utils/Log";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loader
|
|
7
|
+
*/
|
|
8
|
+
export class Loader {
|
|
9
|
+
public static readonly DOMAIN = 'HeapSnapshot';
|
|
10
|
+
public static readonly TAG = 'Loader';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 加载HeapSnapshot文件
|
|
14
|
+
* @param file 文件路径
|
|
15
|
+
* @param log 是否打印日志
|
|
16
|
+
* @returns IHeapSnapshot 对象
|
|
17
|
+
*/
|
|
18
|
+
public static async loadFromFile(file: string, log: boolean = false) : Promise<IHeapSnapshot> {
|
|
19
|
+
if (log) Log.info(Loader.DOMAIN, Loader.TAG, `Loading heapsnapshot from file: ${file}`);
|
|
20
|
+
const snapshot = await getFullHeapFromFile(file);
|
|
21
|
+
if (log) Log.info(Loader.DOMAIN, Loader.TAG, `Loaded heapsnapshot from file: ${file}`);
|
|
22
|
+
return snapshot;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 加载HeapSnapshot文件
|
|
27
|
+
* @param file 文件路径
|
|
28
|
+
* @param options 可选参数选项
|
|
29
|
+
* @param log 是否打印日志
|
|
30
|
+
* @returns IHeapSnapshot 对象
|
|
31
|
+
*/
|
|
32
|
+
public static async loadFromFileOption(file: string,
|
|
33
|
+
options: AnyOptions, log: boolean = false) : Promise<IHeapSnapshot> {
|
|
34
|
+
if (log) Log.info(Loader.DOMAIN, Loader.TAG, `Loading heapsnapshot from file: ${file}`);
|
|
35
|
+
const snapshot = await utils.getSnapshotFromFile(file, options);
|
|
36
|
+
if (log) Log.info(Loader.DOMAIN, Loader.TAG, `Loaded heapsnapshot from file: ${file}`);
|
|
37
|
+
return snapshot
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Heapsnapshot 多文件加载
|
|
42
|
+
* @param files 多文件路径集合
|
|
43
|
+
* @returns IHeapSnapshot 对象集合
|
|
44
|
+
*/
|
|
45
|
+
public static async loadFromFiles(files: Array<string>) : Promise<Array<IHeapSnapshot>> {
|
|
46
|
+
const result = new Array<IHeapSnapshot>();
|
|
47
|
+
files.forEach(async (file) => {
|
|
48
|
+
const heap = await getFullHeapFromFile(file);
|
|
49
|
+
result.push(heap);
|
|
50
|
+
});
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger interface
|
|
3
|
+
*/
|
|
4
|
+
export interface ILogger {
|
|
5
|
+
/**
|
|
6
|
+
* print debug message
|
|
7
|
+
* @param domain log domain
|
|
8
|
+
* @param tag log tag
|
|
9
|
+
* @param message log message
|
|
10
|
+
*/
|
|
11
|
+
debug(domain: string, tag: string, message: string) : void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* print info message
|
|
15
|
+
* @param domain log domain
|
|
16
|
+
* @param tag log tag
|
|
17
|
+
* @param message log message
|
|
18
|
+
*/
|
|
19
|
+
info(domain: string, tag: string, message: string) : void;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* print warn message
|
|
23
|
+
* @param domain log domain
|
|
24
|
+
* @param tag log tag
|
|
25
|
+
* @param message log message
|
|
26
|
+
*/
|
|
27
|
+
warn(domain: string, tag: string, message: string) : void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* print error message
|
|
31
|
+
* @param domain log domain
|
|
32
|
+
* @param tag log tag
|
|
33
|
+
* @param message log message
|
|
34
|
+
*/
|
|
35
|
+
error(domain: string, tag: string, message: string) : void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* print fatal message
|
|
39
|
+
* @param domain log domain
|
|
40
|
+
* @param tag log tag
|
|
41
|
+
* @param message log message
|
|
42
|
+
*/
|
|
43
|
+
fatal(domain: string, tag: string, message: string) : void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Log Type
|
|
48
|
+
*/
|
|
49
|
+
export enum LogType {
|
|
50
|
+
DEBUG = 'DEBUG',
|
|
51
|
+
INFO = 'INFO',
|
|
52
|
+
WARN = 'WARN',
|
|
53
|
+
ERROR = 'ERROR',
|
|
54
|
+
FATAL = 'FATAL'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Loggable interface
|
|
59
|
+
*/
|
|
60
|
+
export interface ILoggable {
|
|
61
|
+
/**
|
|
62
|
+
* Domain
|
|
63
|
+
*/
|
|
64
|
+
DOMAIN: string;
|
|
65
|
+
/**
|
|
66
|
+
* Tag
|
|
67
|
+
*/
|
|
68
|
+
TAG: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Logger class
|
|
73
|
+
*/
|
|
74
|
+
class Logger implements ILogger {
|
|
75
|
+
private _enableTime: boolean;
|
|
76
|
+
|
|
77
|
+
constructor(enableTime: boolean = true) {
|
|
78
|
+
this._enableTime = enableTime;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* print log
|
|
83
|
+
* @param logType log type
|
|
84
|
+
* @param domain domain
|
|
85
|
+
* @param tag tag
|
|
86
|
+
* @param message message
|
|
87
|
+
*/
|
|
88
|
+
private print(logType: LogType, domain: string, tag: string, message: string) {
|
|
89
|
+
const curTime = this._enableTime ? `${new Date().toISOString().replace('Z', '')}` : '*';
|
|
90
|
+
console.log(`${curTime} | [${logType}] | ${domain}-${tag}: ${message}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* print debug message
|
|
95
|
+
* @param domain log domain
|
|
96
|
+
* @param tag log tag
|
|
97
|
+
* @param message log message
|
|
98
|
+
*/
|
|
99
|
+
public debug(domain: string, tag: string, message: string) {
|
|
100
|
+
this.print(LogType.DEBUG, domain, tag, message)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* print info message
|
|
105
|
+
* @param domain log domain
|
|
106
|
+
* @param tag log tag
|
|
107
|
+
* @param message log message
|
|
108
|
+
*/
|
|
109
|
+
public info(domain: string, tag: string, message: string) {
|
|
110
|
+
this.print(LogType.INFO, domain, tag, message)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* print warn message
|
|
115
|
+
* @param domain log domain
|
|
116
|
+
* @param tag log tag
|
|
117
|
+
* @param message log message
|
|
118
|
+
*/
|
|
119
|
+
public warn(domain: string, tag: string, message: string) {
|
|
120
|
+
this.print(LogType.WARN, domain, tag, message)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* print error message
|
|
125
|
+
* @param domain log domain
|
|
126
|
+
* @param tag log tag
|
|
127
|
+
* @param message log message
|
|
128
|
+
*/
|
|
129
|
+
public error(domain: string, tag: string, message: string) {
|
|
130
|
+
this.print(LogType.ERROR, domain, tag, message)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* print fatal message
|
|
135
|
+
* @param domain log domain
|
|
136
|
+
* @param tag log tag
|
|
137
|
+
* @param message log message
|
|
138
|
+
*/
|
|
139
|
+
public fatal(domain: string, tag: string, message: string) {
|
|
140
|
+
this.print(LogType.FATAL, domain, tag, message)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Log class
|
|
146
|
+
*/
|
|
147
|
+
export class Log {
|
|
148
|
+
private static _logger: ILogger = new Logger(true);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* set logger instance
|
|
152
|
+
* @param logger logger instance
|
|
153
|
+
*/
|
|
154
|
+
public static setLogger(logger: ILogger) {
|
|
155
|
+
this._logger = logger;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* print debug message
|
|
160
|
+
* @param domain log domain
|
|
161
|
+
* @param tag log tag
|
|
162
|
+
* @param message log message
|
|
163
|
+
*/
|
|
164
|
+
public static debug(domain: string, tag: string, message: string) {
|
|
165
|
+
this._logger.debug(domain, tag, message);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* print info message
|
|
170
|
+
* @param domain log domain
|
|
171
|
+
* @param tag log tag
|
|
172
|
+
* @param message log message
|
|
173
|
+
*/
|
|
174
|
+
public static info(domain: string, tag: string, message: string) {
|
|
175
|
+
this._logger.info(domain, tag, message);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* print warn message
|
|
180
|
+
* @param domain log domain
|
|
181
|
+
* @param tag log tag
|
|
182
|
+
* @param message log message
|
|
183
|
+
*/
|
|
184
|
+
public static warn(domain: string, tag: string, message: string) {
|
|
185
|
+
this._logger.warn(domain, tag, message);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* print error message
|
|
190
|
+
* @param domain log domain
|
|
191
|
+
* @param tag log tag
|
|
192
|
+
* @param message log message
|
|
193
|
+
*/
|
|
194
|
+
public static error(domain: string, tag: string, message: string) {
|
|
195
|
+
this._logger.error(domain, tag, message);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* print fatal message
|
|
200
|
+
* @param domain log domain
|
|
201
|
+
* @param tag log tag
|
|
202
|
+
* @param message log message
|
|
203
|
+
*/
|
|
204
|
+
public static fatal(domain: string, tag: string, message: string) {
|
|
205
|
+
this._logger.fatal(domain, tag, message);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* print debug message
|
|
210
|
+
* @param instance loggable instance
|
|
211
|
+
* @param message log message
|
|
212
|
+
*/
|
|
213
|
+
public static debugX(instance: ILoggable, message: string) {
|
|
214
|
+
this._logger.debug(instance.DOMAIN, instance.TAG, message);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* print info message
|
|
219
|
+
* @param instance loggable instance
|
|
220
|
+
* @param message log message
|
|
221
|
+
*/
|
|
222
|
+
public static infoX(instance: ILoggable, message: string) {
|
|
223
|
+
this._logger.info(instance.DOMAIN, instance.TAG, message);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* print warn message
|
|
228
|
+
* @param instance loggable instance
|
|
229
|
+
* @param message log message
|
|
230
|
+
*/
|
|
231
|
+
public static warnX(instance: ILoggable, message: string) {
|
|
232
|
+
this._logger.warn(instance.DOMAIN, instance.TAG, message);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* print error message
|
|
237
|
+
* @param instance loggable instance
|
|
238
|
+
* @param message log message
|
|
239
|
+
*/
|
|
240
|
+
public static errorX(instance: ILoggable, message: string) {
|
|
241
|
+
this._logger.error(instance.DOMAIN, instance.TAG, message);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* print fatal message
|
|
246
|
+
* @param instance loggable instance
|
|
247
|
+
* @param message log message
|
|
248
|
+
*/
|
|
249
|
+
public static fatalX(instance: ILoggable, message: string) {
|
|
250
|
+
this._logger.fatal(instance.DOMAIN, instance.TAG, message);
|
|
251
|
+
}
|
|
252
|
+
}
|