-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory-utils.ts
More file actions
104 lines (88 loc) · 3.06 KB
/
memory-utils.ts
File metadata and controls
104 lines (88 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { log } from '@contentstack/cli-utilities';
export interface MemoryStats {
rss: number;
heapTotal: number;
heapUsed: number;
external: number;
arrayBuffers: number;
heapUsedMB: number;
heapTotalMB: number;
rssMB: number;
}
/**
* Simple memory monitoring utilities for asset import
*/
export class MemoryUtils {
private static lastGC: number = 0;
private static gcCooldownMs: number = 5000; // 5 second cooldown between GC calls
/**
* Get current memory usage statistics
*/
static getMemoryStats(): MemoryStats {
const usage = process.memoryUsage();
return {
rss: usage.rss,
heapTotal: usage.heapTotal,
heapUsed: usage.heapUsed,
external: usage.external,
arrayBuffers: usage.arrayBuffers,
heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024 * 100) / 100,
heapTotalMB: Math.round(usage.heapTotal / 1024 / 1024 * 100) / 100,
rssMB: Math.round(usage.rss / 1024 / 1024 * 100) / 100,
};
}
/**
* Check if memory usage exceeds the given threshold
* @param thresholdMB Memory threshold in MB
*/
static checkMemoryPressure(thresholdMB: number = 1024): boolean {
const stats = this.getMemoryStats();
return stats.heapUsedMB > thresholdMB;
}
/**
* Force garbage collection if available and cooldown period has passed
*/
static async forceGarbageCollection(context?: Record<string, any>): Promise<void> {
const now = Date.now();
if (now - this.lastGC < this.gcCooldownMs) {
return; // Skip if cooldown period hasn't passed
}
const beforeStats = this.getMemoryStats();
if (global.gc) {
log.debug(`Forcing garbage collection - heap before: ${beforeStats.heapUsedMB}MB`, context);
global.gc();
// Small delay to allow GC to complete
await new Promise(resolve => setTimeout(resolve, 100));
const afterStats = this.getMemoryStats();
const freedMB = beforeStats.heapUsedMB - afterStats.heapUsedMB;
log.debug(`GC completed - heap after: ${afterStats.heapUsedMB}MB, freed: ${freedMB.toFixed(2)}MB`, context);
this.lastGC = now;
} else {
log.warn('Garbage collection not available. Run with --expose-gc flag for better memory management.', context);
}
}
/**
* Log memory statistics with a given label
*/
static logMemoryStats(label: string, context?: Record<string, any>): void {
const stats = this.getMemoryStats();
log.debug(`${label} - Memory: ${stats.heapUsedMB}MB used / ${stats.heapTotalMB}MB total (RSS: ${stats.rssMB}MB)`, context);
}
/**
* Perform memory cleanup operations
* @param objects Array of objects to null out
*/
static cleanup(...objects: any[]): void {
for (let i = 0; i < objects.length; i++) {
objects[i] = null;
}
}
/**
* Check if we should trigger memory cleanup based on count
* @param count Current count
* @param interval Cleanup interval (default 1000)
*/
static shouldCleanup(count: number, interval: number = 1000): boolean {
return count > 0 && count % interval === 0;
}
}