meminsight-core-publish 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.
Files changed (85) hide show
  1. package/dist/Index.d.ts +21 -0
  2. package/dist/Index.d.ts.map +1 -0
  3. package/dist/Index.js +65 -0
  4. package/dist/analyzer/AnalysisInfo.d.ts +112 -0
  5. package/dist/analyzer/AnalysisInfo.d.ts.map +1 -0
  6. package/dist/analyzer/AnalysisInfo.js +217 -0
  7. package/dist/analyzer/ArkAnalyzer.d.ts +30 -0
  8. package/dist/analyzer/ArkAnalyzer.d.ts.map +1 -0
  9. package/dist/analyzer/ArkAnalyzer.js +52 -0
  10. package/dist/analyzer/ArkCmpCfg.d.ts +15 -0
  11. package/dist/analyzer/ArkCmpCfg.d.ts.map +1 -0
  12. package/dist/analyzer/ArkCmpCfg.js +15 -0
  13. package/dist/analyzer/ArkCompareAnalyzer.d.ts +52 -0
  14. package/dist/analyzer/ArkCompareAnalyzer.d.ts.map +1 -0
  15. package/dist/analyzer/ArkCompareAnalyzer.js +144 -0
  16. package/dist/analyzer/ArkLeakAnalyzer.d.ts +14 -0
  17. package/dist/analyzer/ArkLeakAnalyzer.d.ts.map +1 -0
  18. package/dist/analyzer/ArkLeakAnalyzer.js +18 -0
  19. package/dist/analyzer/ArkSerializer.d.ts +18 -0
  20. package/dist/analyzer/ArkSerializer.d.ts.map +1 -0
  21. package/dist/analyzer/ArkSerializer.js +155 -0
  22. package/dist/analyzer/ArkStatAnalyzer.d.ts +56 -0
  23. package/dist/analyzer/ArkStatAnalyzer.d.ts.map +1 -0
  24. package/dist/analyzer/ArkStatAnalyzer.js +224 -0
  25. package/dist/analyzer/ArkStatCfg.d.ts +42 -0
  26. package/dist/analyzer/ArkStatCfg.d.ts.map +1 -0
  27. package/dist/analyzer/ArkStatCfg.js +42 -0
  28. package/dist/analyzer/ArkTracePath.d.ts +90 -0
  29. package/dist/analyzer/ArkTracePath.d.ts.map +1 -0
  30. package/dist/analyzer/ArkTracePath.js +245 -0
  31. package/dist/analyzer/ArkTracer.d.ts +17 -0
  32. package/dist/analyzer/ArkTracer.d.ts.map +1 -0
  33. package/dist/analyzer/ArkTracer.js +27 -0
  34. package/dist/analyzer/ArkXAnalyzer.d.ts +69 -0
  35. package/dist/analyzer/ArkXAnalyzer.d.ts.map +1 -0
  36. package/dist/analyzer/ArkXAnalyzer.js +616 -0
  37. package/dist/analyzer/IAnalyzer.d.ts +25 -0
  38. package/dist/analyzer/IAnalyzer.d.ts.map +1 -0
  39. package/dist/analyzer/IAnalyzer.js +2 -0
  40. package/dist/file/FileReader.d.ts +51 -0
  41. package/dist/file/FileReader.d.ts.map +1 -0
  42. package/dist/file/FileReader.js +110 -0
  43. package/dist/file/FileService.d.ts +23 -0
  44. package/dist/file/FileService.d.ts.map +1 -0
  45. package/dist/file/FileService.js +65 -0
  46. package/dist/file/FileWriter.d.ts +82 -0
  47. package/dist/file/FileWriter.d.ts.map +1 -0
  48. package/dist/file/FileWriter.js +160 -0
  49. package/dist/report/Reporter.d.ts +27 -0
  50. package/dist/report/Reporter.d.ts.map +1 -0
  51. package/dist/report/Reporter.js +61 -0
  52. package/dist/report/templates/template.d.ts +3 -0
  53. package/dist/report/templates/template.d.ts.map +1 -0
  54. package/dist/report/templates/template.js +106 -0
  55. package/dist/shell/DeviceShell.d.ts +96 -0
  56. package/dist/shell/DeviceShell.d.ts.map +1 -0
  57. package/dist/shell/DeviceShell.js +180 -0
  58. package/dist/shell/Shell.d.ts +52 -0
  59. package/dist/shell/Shell.d.ts.map +1 -0
  60. package/dist/shell/Shell.js +79 -0
  61. package/dist/types/Constants.d.ts +15 -0
  62. package/dist/types/Constants.d.ts.map +1 -0
  63. package/dist/types/Constants.js +18 -0
  64. package/dist/types/LeakTypes.d.ts +18 -0
  65. package/dist/types/LeakTypes.d.ts.map +1 -0
  66. package/dist/types/LeakTypes.js +2 -0
  67. package/dist/types/OhosTypes.d.ts +74 -0
  68. package/dist/types/OhosTypes.d.ts.map +1 -0
  69. package/dist/types/OhosTypes.js +83 -0
  70. package/dist/utils/Common.d.ts +14 -0
  71. package/dist/utils/Common.d.ts.map +1 -0
  72. package/dist/utils/Common.js +38 -0
  73. package/dist/utils/Finder.d.ts +163 -0
  74. package/dist/utils/Finder.d.ts.map +1 -0
  75. package/dist/utils/Finder.js +355 -0
  76. package/dist/utils/Loader.d.ts +30 -0
  77. package/dist/utils/Loader.d.ts.map +1 -0
  78. package/dist/utils/Loader.js +71 -0
  79. package/dist/utils/Log.d.ts +140 -0
  80. package/dist/utils/Log.d.ts.map +1 -0
  81. package/dist/utils/Log.js +177 -0
  82. package/dist/utils/Output.d.ts +126 -0
  83. package/dist/utils/Output.d.ts.map +1 -0
  84. package/dist/utils/Output.js +225 -0
  85. package/package.json +61 -0
@@ -0,0 +1,616 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.ArkXAnalyzer = exports.ArkXSortType = void 0;
46
+ const path = __importStar(require("path"));
47
+ const fs = __importStar(require("fs"));
48
+ const heap_analysis_1 = require("@memlab/heap-analysis");
49
+ const ArkAnalyzer_1 = require("./ArkAnalyzer");
50
+ const Finder_1 = require("../utils/Finder");
51
+ const Log_1 = require("../utils/Log");
52
+ const AnalysisInfo_1 = require("./AnalysisInfo");
53
+ const Reporter_1 = require("../report/Reporter");
54
+ var ArkXSortType;
55
+ (function (ArkXSortType) {
56
+ ArkXSortType[ArkXSortType["BY_RETAINED_SIZE"] = 0] = "BY_RETAINED_SIZE";
57
+ ArkXSortType[ArkXSortType["BY_COUNT"] = 1] = "BY_COUNT";
58
+ })(ArkXSortType || (exports.ArkXSortType = ArkXSortType = {}));
59
+ /**
60
+ * Ark Heapsnapshot 统计分析器
61
+ */
62
+ class ArkXAnalyzer extends ArkAnalyzer_1.ArkAnalyzer {
63
+ constructor() {
64
+ super();
65
+ this.DOMAIN = 'meminsight';
66
+ this.TAG = ArkXAnalyzer.name;
67
+ this.type = 'ark-x-analyzer';
68
+ this.config = {
69
+ topN: 10,
70
+ sortType: ArkXSortType.BY_RETAINED_SIZE,
71
+ tags: []
72
+ };
73
+ }
74
+ setConfig(config) {
75
+ this.config = config;
76
+ }
77
+ analyze(args) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ let file = args[0];
80
+ let list = args[1];
81
+ let topN = args[2];
82
+ let sortType = args[3];
83
+ let tags = args[4];
84
+ // 处理文件路径
85
+ this.snapshotFiles = [];
86
+ if (file !== undefined && file !== '') {
87
+ this.snapshotFiles.push(path.resolve(file));
88
+ }
89
+ if (list !== undefined && list.length > 0) {
90
+ list.forEach(item => {
91
+ let itemPath = path.resolve(item);
92
+ if (this.snapshotFiles.indexOf(itemPath) === -1) {
93
+ this.snapshotFiles.push(itemPath);
94
+ }
95
+ });
96
+ }
97
+ console.info(`Heapsnapshot Files:`);
98
+ this.snapshotFiles.forEach(item => {
99
+ console.info(item);
100
+ });
101
+ // 设置 config
102
+ this.config.topN = topN <= 0 ? 10 : topN;
103
+ this.config.sortType = sortType == 0 ? ArkXSortType.BY_RETAINED_SIZE : ArkXSortType.BY_COUNT;
104
+ console.log(`TopN: ${topN}\nSortType: ${this.config.sortType.toString()}`);
105
+ if (tags != undefined && tags.length > 0) {
106
+ this.config.tags = tags;
107
+ console.info(`Tags:`);
108
+ tags.forEach(tag => {
109
+ console.info(tag);
110
+ });
111
+ }
112
+ for (let i = 0; i < this.snapshotFiles.length; i++) {
113
+ let filepath = this.snapshotFiles.at(i);
114
+ if (!fs.existsSync(filepath)) {
115
+ Log_1.Log.errorX(this, `File not found, ${filepath}`);
116
+ return;
117
+ }
118
+ let infos = yield this.analyzeOne(filepath);
119
+ let datas = [];
120
+ infos.forEach((info) => {
121
+ let data = info.toReportData();
122
+ datas.push(data);
123
+ });
124
+ Reporter_1.ReporterHTML.generateByTemplate(datas, path.basename(filepath));
125
+ }
126
+ });
127
+ }
128
+ analyzeOne(filepath) {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ let snapshot;
131
+ const results = [];
132
+ try {
133
+ console.info("Start to parse heapsnapshot: ", filepath);
134
+ snapshot = yield (0, heap_analysis_1.getFullHeapFromFile)(filepath);
135
+ if (snapshot === undefined) {
136
+ console.info(`Failed to parse heapsnapshot: ${filepath}, snapshot is undefined.`);
137
+ return results;
138
+ }
139
+ console.info('Success to parse heapsnapshot: ', filepath);
140
+ let result;
141
+ let TopN = this.config.topN;
142
+ // 同类名的基础对象统计&聚合 (如 JSObject, global_env...)
143
+ const baseObjectWithSameNameList = [
144
+ 'JSObject', 'js_shared_object',
145
+ 'js_array', 'js_map', 'js_set',
146
+ 'js_proxy', 'js_native_pointer', 'js_weak_ref'
147
+ ];
148
+ baseObjectWithSameNameList.forEach(objectName => {
149
+ result = this.statSpecificObjectNameByDistance(snapshot, objectName);
150
+ results.push(result);
151
+ result = this.aggregateSpecificObjectNameByReference(snapshot, objectName, TopN);
152
+ results.push(result);
153
+ result = this.aggregateSpecificObjectNameByDistance1(snapshot, objectName, TopN);
154
+ results.push(result);
155
+ });
156
+ // 同类型的基础对象统计&聚合
157
+ const baseObjectWithSameTypeList = ['string', 'system', 'framework', 'array'];
158
+ baseObjectWithSameTypeList.forEach(objectType => {
159
+ result = this.aggregateSpecificObjectInfoByClassName(snapshot, objectType, [], TopN);
160
+ results.push(result);
161
+ result = this.aggregateSpecificObjectInfoByReference(snapshot, '', objectType, [], TopN);
162
+ results.push(result);
163
+ });
164
+ // 业务对象统计&聚合
165
+ const tags = this.config.tags;
166
+ if (tags.length > 0) {
167
+ result = this.aggregateSpecificObjectInfoByClassName(snapshot, '', tags, TopN);
168
+ results.push(result);
169
+ result = this.aggregateSpecificObjectInfoByReference(snapshot, '', '', tags, TopN);
170
+ results.push(result);
171
+ }
172
+ return results;
173
+ }
174
+ catch (error) {
175
+ console.error('Failed to parse heapsnapshot, ', error);
176
+ }
177
+ finally {
178
+ // TODO:
179
+ }
180
+ return [];
181
+ });
182
+ }
183
+ /**
184
+ * 指定类名对象按 Distance 统计
185
+ */
186
+ statSpecificObjectNameByDistance(snapshot, objectName) {
187
+ console.log(`\n\n========================${objectName} 对象按 Distance 统计=========================\n`);
188
+ let totalHeapSize = 0;
189
+ let totalRetainSize = 0;
190
+ let totalSelfSize = 0;
191
+ let totalCount = 0;
192
+ let countMap = new Map();
193
+ let retainSizeMap = new Map();
194
+ let selfSizeMap = new Map();
195
+ snapshot.nodes.forEach((node) => {
196
+ totalHeapSize += node.self_size;
197
+ if (node.name === objectName) {
198
+ totalCount++;
199
+ totalRetainSize += node.retainedSize;
200
+ totalSelfSize += node.self_size;
201
+ let distance = Finder_1.Finder.getShortestPath(node)[2];
202
+ countMap.set(distance, (countMap.get(distance) || 0) + 1);
203
+ selfSizeMap.set(distance, (selfSizeMap.get(distance) || 0) + node.self_size);
204
+ retainSizeMap.set(distance, (retainSizeMap.get(distance) || 0) + node.retainedSize);
205
+ }
206
+ });
207
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
208
+ console.log(`Total ${objectName} Self Size: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
209
+ console.log(`Total ${objectName} Retained Size: ${(totalRetainSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainSize / totalHeapSize * 100).toFixed(2)}%`);
210
+ console.log(`Total ${objectName} Count: ${totalCount}`);
211
+ // 按距离统计取全部数据
212
+ let sortedeMap;
213
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
214
+ console.log(`\n${objectName} Info By Count:`);
215
+ sortedeMap = new Map([...countMap].sort((a, b) => b[1] - a[1]));
216
+ }
217
+ else {
218
+ console.log(`\n${objectName} Info By Retained Size:`);
219
+ sortedeMap = new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]));
220
+ }
221
+ let num = 1;
222
+ let distanceInfos = [];
223
+ sortedeMap.forEach((value, key) => {
224
+ let distanceInfo = new AnalysisInfo_1.DistanceInfo();
225
+ distanceInfo.objectNameOrType = objectName;
226
+ distanceInfo.count = value;
227
+ distanceInfo.distance = key;
228
+ distanceInfo.retainedSize = retainSizeMap.get(key);
229
+ distanceInfo.selfSize = selfSizeMap.get(key);
230
+ distanceInfo.retainedSizeTotalHeapPercent = distanceInfo.retainedSize / totalHeapSize * 100;
231
+ distanceInfo.selfSizeTotalHeapPercent = distanceInfo.selfSize / totalHeapSize * 100;
232
+ distanceInfo.retainedSizeTotalRetainedPercent = distanceInfo.retainedSize / totalRetainSize * 100;
233
+ distanceInfo.selfSizeTotalSelfPercent = distanceInfo.selfSize / totalSelfSize * 100;
234
+ distanceInfos.push(distanceInfo);
235
+ console.log(`Index-${num++}, ${distanceInfo.toString()}`);
236
+ });
237
+ let targetNode = new AnalysisInfo_1.StatisticsByDistance();
238
+ targetNode.type = objectName;
239
+ targetNode.desc = `指定类名对象按 Distance 统计`;
240
+ targetNode.totalCount = totalCount;
241
+ targetNode.totalHeapSize = totalHeapSize;
242
+ targetNode.totalRetainedSize = totalRetainSize;
243
+ targetNode.totalSelfSize = totalSelfSize;
244
+ targetNode.distanceInfos = distanceInfos;
245
+ return targetNode;
246
+ }
247
+ /**
248
+ * 指定类名的最短引用链聚合
249
+ * @param snapshot 快照
250
+ * @param topNum TopN
251
+ */
252
+ aggregateSpecificObjectNameByReference(snapshot, objectName, topNum = 10) {
253
+ console.log(`\n\n========================${objectName} 对象按最短引用链聚合=========================\n`);
254
+ let totalHeapSize = 0;
255
+ let totalRetainSize = 0;
256
+ let totalSelfSize = 0;
257
+ let totalCount = 0;
258
+ let countMap = new Map();
259
+ let retainSizeMap = new Map();
260
+ let selfSizeMap = new Map();
261
+ snapshot.nodes.forEach((node) => {
262
+ totalHeapSize += node.self_size;
263
+ if (node.name === objectName) {
264
+ totalCount++;
265
+ totalRetainSize += node.retainedSize;
266
+ totalSelfSize += node.self_size;
267
+ let [shortestPathIds, shortestPathStrs] = Finder_1.Finder.getShortestPath(node);
268
+ let shortestPathStr = shortestPathStrs.join(' <- ');
269
+ countMap.set(shortestPathStr, (countMap.get(shortestPathStr) || 0) + 1);
270
+ retainSizeMap.set(shortestPathStr, (retainSizeMap.get(shortestPathStr) || 0) + node.retainedSize);
271
+ selfSizeMap.set(shortestPathStr, (selfSizeMap.get(shortestPathStr) || 0) + node.self_size);
272
+ }
273
+ });
274
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
275
+ console.log(`Total ${objectName} Self Size: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
276
+ console.log(`Total ${objectName} Retained Size: ${(totalRetainSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainSize / totalHeapSize * 100).toFixed(2)}%`);
277
+ console.log(`Total ${objectName} Count: ${totalCount}`);
278
+ let sortedeMap;
279
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
280
+ console.log(`\n${objectName} Info By Count:`);
281
+ sortedeMap = countMap.size < topNum
282
+ ? new Map([...countMap].sort((a, b) => b[1] - a[1]))
283
+ : new Map([...countMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
284
+ }
285
+ else {
286
+ console.log(`\n${objectName} Info By Retained Size:`);
287
+ sortedeMap = retainSizeMap.size < topNum
288
+ ? new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]))
289
+ : new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
290
+ }
291
+ let num = 1;
292
+ let shortestPathInfos = [];
293
+ sortedeMap.forEach((_, key) => {
294
+ let info = new AnalysisInfo_1.ShortestPathInfo();
295
+ info.shortestPathStr = key;
296
+ info.count = countMap.get(key);
297
+ info.retainedSize = retainSizeMap.get(key);
298
+ info.selfSize = selfSizeMap.get(key);
299
+ info.retainedSizeTotalHeapPercent = info.retainedSize / totalHeapSize * 100;
300
+ info.selfSizeTotalHeapPercent = info.selfSize / totalHeapSize * 100;
301
+ info.retainedSizeTotalRetainedPercent = info.retainedSize / totalRetainSize * 100;
302
+ info.selfSizeTotalSelfPercent = info.selfSize / totalSelfSize * 100;
303
+ shortestPathInfos.push(info);
304
+ console.log(`Index-${num++}, ${info.toString()}`);
305
+ });
306
+ let targetNode = new AnalysisInfo_1.AggregationByShortestPath();
307
+ targetNode.shortestPathInfos = [];
308
+ targetNode.type = objectName;
309
+ targetNode.desc = `按最短引用链聚合`;
310
+ targetNode.totalHeapSize = totalHeapSize;
311
+ targetNode.totalRetainedSize = totalRetainSize;
312
+ targetNode.totalSelfSize = totalSelfSize;
313
+ targetNode.totalCount = totalCount;
314
+ targetNode.shortestPathInfos = shortestPathInfos;
315
+ return targetNode;
316
+ }
317
+ /**
318
+ * 指定类名的Distance=1的对象属性按最短引用链聚合
319
+ * @param snapshot 快照
320
+ * @param objectName
321
+ * @param topNum TopN
322
+ */
323
+ aggregateSpecificObjectNameByDistance1(snapshot, objectName, topNum = 10, maxRetainedSize = -1) {
324
+ console.log(`\n========================${objectName} 按 Distance=1 的对象属性聚合分析=========================\n`);
325
+ let totalHeapSize = 0;
326
+ let totalRetainedSize = 0;
327
+ let totalSelfSize = 0;
328
+ let totalCount = 0;
329
+ let countMap = new Map();
330
+ let retainedSizeMap = new Map();
331
+ let selfSizeMap = new Map();
332
+ snapshot.nodes.forEach((node) => {
333
+ totalHeapSize += node.self_size;
334
+ if (node.name !== objectName) {
335
+ return;
336
+ }
337
+ if (node.retainedSize / 1024 < maxRetainedSize) {
338
+ return;
339
+ }
340
+ let distance = Finder_1.Finder.getShortestPath(node)[2];
341
+ if (distance > 1) {
342
+ return;
343
+ }
344
+ node.forEachReference((edge) => {
345
+ let toNode = edge.toNode;
346
+ totalRetainedSize += toNode.retainedSize;
347
+ totalSelfSize += toNode.self_size;
348
+ totalCount++;
349
+ let [shortestPathIds, shortestPathStrs, distance] = Finder_1.Finder.getShortestPath(toNode);
350
+ let shortestPath = shortestPathStrs.join(' <- ');
351
+ countMap.set(shortestPath, (countMap.get(shortestPath) || 0) + 1);
352
+ retainedSizeMap.set(shortestPath, (retainedSizeMap.get(shortestPath) || 0) + toNode.retainedSize);
353
+ selfSizeMap.set(shortestPath, (selfSizeMap.get(shortestPath) || 0) + toNode.self_size);
354
+ });
355
+ });
356
+ // 打印总堆大小
357
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
358
+ console.log(`All Properties Retained Size in ${objectName} Distance=1: ${(totalRetainedSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainedSize / totalHeapSize * 100).toFixed(2)}%`);
359
+ console.log(`All Properties Self Size in ${objectName} Distance=1: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
360
+ console.log(`Count of Properties in ${objectName} Distance=1: ${totalCount}`);
361
+ let sortedeMap;
362
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
363
+ console.log(`\n${objectName} Info By Count:`);
364
+ sortedeMap = countMap.size < topNum
365
+ ? new Map([...countMap].sort((a, b) => b[1] - a[1]))
366
+ : new Map([...countMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
367
+ }
368
+ else {
369
+ console.log(`\n${objectName} Info By Retained Size:`);
370
+ sortedeMap = retainedSizeMap.size < topNum
371
+ ? new Map([...retainedSizeMap].sort((a, b) => b[1] - a[1]))
372
+ : new Map([...retainedSizeMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
373
+ }
374
+ let propInfos = [];
375
+ let num = 1;
376
+ sortedeMap.forEach((_, key) => {
377
+ let propInfo = new AnalysisInfo_1.PropertyInfo();
378
+ propInfo.propName = '-';
379
+ propInfo.propShortestPath = key;
380
+ propInfo.retainedSize = retainedSizeMap.get(key);
381
+ propInfo.selfSize = selfSizeMap.get(key);
382
+ propInfo.count = countMap.get(key);
383
+ propInfo.retainedSizeTotalHeapPercent = propInfo.retainedSize / totalHeapSize * 100;
384
+ propInfo.selfSizeTotalHeapPercent = propInfo.selfSize / totalHeapSize * 100;
385
+ propInfo.retainedSizeTotalRetainedPercent = propInfo.retainedSize / totalRetainedSize * 100;
386
+ propInfo.selfSizeTotalSelfPercent = propInfo.selfSize / totalSelfSize * 100;
387
+ propInfos.push(propInfo);
388
+ console.log(`${num++}.${propInfo.toString()}`);
389
+ });
390
+ let targetNode = new AnalysisInfo_1.AggregationByProperty();
391
+ targetNode.type = objectName;
392
+ targetNode.desc = `按 Distance=1 的对象属性聚合`;
393
+ targetNode.totalCount = totalCount;
394
+ targetNode.totalHeapSize = totalHeapSize;
395
+ targetNode.totalRetainedSize = totalRetainedSize;
396
+ targetNode.totalSelfSize = totalSelfSize;
397
+ targetNode.propertyInfos = propInfos;
398
+ return targetNode;
399
+ }
400
+ /**
401
+ * 指定类名的最短引用链聚合
402
+ * @param snapshot 快照
403
+ * @param topNum TopN
404
+ */
405
+ aggregateSpecificObjectTypeByReference(snapshot, objectType, topNum = 10) {
406
+ console.log(`\n\n========================${objectType} 类型的对象按最短引用链聚合=========================\n`);
407
+ let totalHeapSize = 0;
408
+ let totalRetainSize = 0;
409
+ let totalSelfSize = 0;
410
+ let totalCount = 0;
411
+ let countMap = new Map();
412
+ let retainSizeMap = new Map();
413
+ let selfSizeMap = new Map();
414
+ snapshot.nodes.forEach((node) => {
415
+ totalHeapSize += node.self_size;
416
+ if (node.type === objectType) {
417
+ totalCount++;
418
+ totalRetainSize += node.retainedSize;
419
+ totalSelfSize += node.self_size;
420
+ let [shortestPathIds, shortestPathStrs] = Finder_1.Finder.getShortestPath(node);
421
+ let shortestPathStr = shortestPathStrs.join(' <- ');
422
+ countMap.set(shortestPathStr, (countMap.get(shortestPathStr) || 0) + 1);
423
+ retainSizeMap.set(shortestPathStr, (retainSizeMap.get(shortestPathStr) || 0) + node.retainedSize);
424
+ selfSizeMap.set(shortestPathStr, (selfSizeMap.get(shortestPathStr) || 0) + node.self_size);
425
+ }
426
+ });
427
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
428
+ console.log(`Total Type ${objectType} Self Size: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
429
+ console.log(`Total Type ${objectType} Retained Size: ${(totalRetainSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainSize / totalHeapSize * 100).toFixed(2)}%`);
430
+ console.log(`Total Type ${objectType} Count: ${totalCount}`);
431
+ let sortedeMap;
432
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
433
+ console.log(`\nType ${objectType} Info By Count:`);
434
+ sortedeMap = countMap.size < topNum
435
+ ? new Map([...countMap].sort((a, b) => b[1] - a[1]))
436
+ : new Map([...countMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
437
+ }
438
+ else {
439
+ console.log(`\nType ${objectType} Info By Retained Size:`);
440
+ sortedeMap = retainSizeMap.size < topNum
441
+ ? new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]))
442
+ : new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
443
+ }
444
+ let num = 1;
445
+ let shortestPathInfos = [];
446
+ sortedeMap.forEach((_, key) => {
447
+ let info = new AnalysisInfo_1.ShortestPathInfo();
448
+ info.shortestPathStr = key;
449
+ info.count = countMap.get(key);
450
+ info.retainedSize = retainSizeMap.get(key);
451
+ info.selfSize = selfSizeMap.get(key);
452
+ info.retainedSizeTotalHeapPercent = info.retainedSize / totalHeapSize * 100;
453
+ info.selfSizeTotalHeapPercent = info.selfSize / totalHeapSize * 100;
454
+ info.retainedSizeTotalRetainedPercent = info.retainedSize / totalRetainSize * 100;
455
+ info.selfSizeTotalSelfPercent = info.selfSize / totalSelfSize * 100;
456
+ shortestPathInfos.push(info);
457
+ console.log(`Index-${num++}, ${info.toString()}`);
458
+ });
459
+ let targetNode = new AnalysisInfo_1.AggregationByShortestPath();
460
+ targetNode.type = objectType;
461
+ targetNode.desc = `按最短引用链聚合`;
462
+ targetNode.totalHeapSize = totalHeapSize;
463
+ targetNode.totalRetainedSize = totalRetainSize;
464
+ targetNode.totalSelfSize = totalSelfSize;
465
+ targetNode.totalCount = totalCount;
466
+ targetNode.shortestPathInfos = shortestPathInfos;
467
+ return targetNode;
468
+ }
469
+ /**
470
+ * 指定类名/类型/标签的最短引用链聚合
471
+ * @param snapshot 快照
472
+ * @param objectName 对象类名,为空则不判断
473
+ * @param objectType 对象类型,为空则不判断
474
+ * @param tags 对象标签,比如业务标签
475
+ * @param topNum TopN
476
+ */
477
+ aggregateSpecificObjectInfoByReference(snapshot, objectName, objectType, tags, topNum = 10) {
478
+ console.log(`\n\n========================Name:${objectName}-Type:${objectType}-Tags:${tags} 对象按最短引用链聚合=========================\n`);
479
+ let totalHeapSize = 0;
480
+ let totalRetainSize = 0;
481
+ let totalSelfSize = 0;
482
+ let totalCount = 0;
483
+ let countMap = new Map();
484
+ let retainSizeMap = new Map();
485
+ let selfSizeMap = new Map();
486
+ snapshot.nodes.forEach((node) => {
487
+ totalHeapSize += node.self_size;
488
+ if ((node.name === objectName)
489
+ || (node.type === objectType)
490
+ || tags.some(tag => node.name.includes(tag))) {
491
+ totalCount++;
492
+ totalRetainSize += node.retainedSize;
493
+ totalSelfSize += node.self_size;
494
+ let [shortestPathIds, shortestPathStrs] = Finder_1.Finder.getShortestPath(node);
495
+ let shortestPathStr = shortestPathStrs.join(' <- ');
496
+ countMap.set(shortestPathStr, (countMap.get(shortestPathStr) || 0) + 1);
497
+ retainSizeMap.set(shortestPathStr, (retainSizeMap.get(shortestPathStr) || 0) + node.retainedSize);
498
+ selfSizeMap.set(shortestPathStr, (selfSizeMap.get(shortestPathStr) || 0) + node.self_size);
499
+ }
500
+ });
501
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
502
+ console.log(`Total Self Size: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
503
+ console.log(`Total Retained Size: ${(totalRetainSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainSize / totalHeapSize * 100).toFixed(2)}%`);
504
+ console.log(`Total Count: ${totalCount}`);
505
+ let sortedeMap;
506
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
507
+ console.log(`\nInfo By Count:`);
508
+ sortedeMap = countMap.size < topNum
509
+ ? new Map([...countMap].sort((a, b) => b[1] - a[1]))
510
+ : new Map([...countMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
511
+ }
512
+ else {
513
+ console.log(`\nInfo By Retained Size:`);
514
+ sortedeMap = retainSizeMap.size < topNum
515
+ ? new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]))
516
+ : new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
517
+ }
518
+ let num = 1;
519
+ let shortestPathInfos = [];
520
+ sortedeMap.forEach((_, key) => {
521
+ let info = new AnalysisInfo_1.ShortestPathInfo();
522
+ info.shortestPathStr = key;
523
+ info.count = countMap.get(key);
524
+ info.retainedSize = retainSizeMap.get(key);
525
+ info.selfSize = selfSizeMap.get(key);
526
+ info.retainedSizeTotalHeapPercent = info.retainedSize / totalHeapSize * 100;
527
+ info.selfSizeTotalHeapPercent = info.selfSize / totalHeapSize * 100;
528
+ info.retainedSizeTotalRetainedPercent = info.retainedSize / totalRetainSize * 100;
529
+ info.selfSizeTotalSelfPercent = info.selfSize / totalSelfSize * 100;
530
+ shortestPathInfos.push(info);
531
+ console.log(`Index-${num++}, ${info.toString()}`);
532
+ });
533
+ let targetNode = new AnalysisInfo_1.AggregationByShortestPath();
534
+ targetNode.type = `[Name:${objectName}-Type:${objectType}-Tags:${tags}]`;
535
+ targetNode.desc = `按指定类名/类型/标签的对象的最短引用链聚合`;
536
+ targetNode.totalHeapSize = totalHeapSize;
537
+ targetNode.totalRetainedSize = totalRetainSize;
538
+ targetNode.totalSelfSize = totalSelfSize;
539
+ targetNode.totalCount = totalCount;
540
+ targetNode.shortestPathInfos = shortestPathInfos;
541
+ return targetNode;
542
+ }
543
+ /**
544
+ * 指定类名/类型/标签的最短引用链聚合
545
+ * @param snapshot 快照
546
+ * @param objectType 对象类型,为空则不判断
547
+ * @param tags 对象标签,比如业务标签
548
+ * @param topNum TopN
549
+ */
550
+ aggregateSpecificObjectInfoByClassName(snapshot, objectType, tags, topNum = 10) {
551
+ console.log(`\n\n========================Type:${objectType}-Tags:${tags} 对象按对象名称聚合=========================\n`);
552
+ let totalHeapSize = 0;
553
+ let totalRetainSize = 0;
554
+ let totalSelfSize = 0;
555
+ let totalCount = 0;
556
+ let countMap = new Map();
557
+ let retainSizeMap = new Map();
558
+ let selfSizeMap = new Map();
559
+ snapshot.nodes.forEach((node) => {
560
+ totalHeapSize += node.self_size;
561
+ if ((node.type === objectType) || tags.some(tag => node.name.includes(tag))) {
562
+ totalCount++;
563
+ totalRetainSize += node.retainedSize;
564
+ totalSelfSize += node.self_size;
565
+ let name = Finder_1.Finder.getClassName(node.name);
566
+ countMap.set(name, (countMap.get(name) || 0) + 1);
567
+ retainSizeMap.set(name, (retainSizeMap.get(name) || 0) + node.retainedSize);
568
+ selfSizeMap.set(name, (selfSizeMap.get(name) || 0) + node.self_size);
569
+ }
570
+ });
571
+ console.log(`Total Heap Size: ${(totalHeapSize / 1024 / 1024).toFixed(2)} MB`);
572
+ console.log(`Total Self Size: ${(totalSelfSize / 1024).toFixed(2)} KB, Ratio: ${(totalSelfSize / totalHeapSize * 100).toFixed(2)}%`);
573
+ console.log(`Total Retained Size: ${(totalRetainSize / 1024).toFixed(2)} KB, Ratio: ${(totalRetainSize / totalHeapSize * 100).toFixed(2)}%`);
574
+ console.log(`Total Count: ${totalCount}`);
575
+ let sortedeMap;
576
+ if (this.config.sortType === ArkXSortType.BY_COUNT) {
577
+ console.log(`\nInfo By Count:`);
578
+ sortedeMap = countMap.size < topNum
579
+ ? new Map([...countMap].sort((a, b) => b[1] - a[1]))
580
+ : new Map([...countMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
581
+ }
582
+ else {
583
+ console.log(`\nInfo By Retained Size:`);
584
+ sortedeMap = retainSizeMap.size < topNum
585
+ ? new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]))
586
+ : new Map([...retainSizeMap].sort((a, b) => b[1] - a[1]).slice(0, topNum));
587
+ }
588
+ let num = 1;
589
+ let classInfos = [];
590
+ sortedeMap.forEach((_, key) => {
591
+ let info = new AnalysisInfo_1.ClassInfo();
592
+ info.className = key;
593
+ info.count = countMap.get(key);
594
+ info.retainedSize = retainSizeMap.get(key);
595
+ info.selfSize = selfSizeMap.get(key);
596
+ info.retainedSizeTotalHeapPercent = info.retainedSize / totalHeapSize * 100;
597
+ info.selfSizeTotalHeapPercent = info.selfSize / totalHeapSize * 100;
598
+ info.retainedSizeTotalRetainedPercent = info.retainedSize / totalRetainSize * 100;
599
+ info.selfSizeTotalSelfPercent = info.selfSize / totalSelfSize * 100;
600
+ classInfos.push(info);
601
+ console.log(`Index-${num++}, ${info.toString()}`);
602
+ });
603
+ let targetNode = new AnalysisInfo_1.AggregationByClassName();
604
+ targetNode.type = `[Type:${objectType}-Tags:${tags}]`;
605
+ targetNode.desc = `按对象类型/标签聚合`;
606
+ targetNode.totalHeapSize = totalHeapSize;
607
+ targetNode.totalRetainedSize = totalRetainSize;
608
+ targetNode.totalSelfSize = totalSelfSize;
609
+ targetNode.totalCount = totalCount;
610
+ targetNode.classInfos = classInfos;
611
+ return targetNode;
612
+ }
613
+ }
614
+ exports.ArkXAnalyzer = ArkXAnalyzer;
615
+ ArkXAnalyzer.NAME = 'ark-x-analyzer';
616
+ ArkXAnalyzer.DESC = "Analyze heapsnapshot files and aggregate & statistics.";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Analyzer interface
3
+ */
4
+ export interface IAnalyzer {
5
+ /**
6
+ * initialize command program
7
+ * @param proc command
8
+ */
9
+ analyze(args: any[]): any;
10
+ /**
11
+ * set configuration
12
+ * @param cfg configuration
13
+ */
14
+ setConfig(cfg: any): void;
15
+ /**
16
+ * get configuration
17
+ * @return configuration
18
+ */
19
+ getConfig(): any;
20
+ /**
21
+ * get type
22
+ */
23
+ getType(): string;
24
+ }
25
+ //# sourceMappingURL=IAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/IAnalyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,GAAI,GAAG,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,GAAG,GAAI,IAAI,CAAC;IAE3B;;;OAGG;IACH,SAAS,IAAI,GAAG,CAAC;IAEjB;;OAEG;IACH,OAAO,IAAI,MAAM,CAAC;CACrB"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });