node-oom-heapdump
Advanced tools
Comparing version 1.1.1 to 1.1.2
15
index.js
@@ -87,2 +87,7 @@ let nodeOomLib = require("./lib"); | ||
} | ||
if (options.OOMImplementation === undefined){ | ||
// default is the "new" implementation | ||
// the other option is "GC_MONITORING", which is the old implementation (which is less impacted by OoMKiller) | ||
options.OOMImplementation = "NATIVE_HOOK"; | ||
} | ||
if (options.port === undefined) { | ||
@@ -96,2 +101,12 @@ options.port = 9229; | ||
} | ||
if (options.limit === undefined) { | ||
options.limit = 3; | ||
} else { | ||
options.limit = parseInt(options.limit); | ||
} | ||
if (options.threshold === undefined) { | ||
options.threshold = 70; | ||
} else { | ||
options.threshold = parseInt(options.threshold); | ||
} | ||
if (options.addTimestamp === undefined) { | ||
@@ -98,0 +113,0 @@ options.addTimestamp = false; |
@@ -11,8 +11,45 @@ let cp = require("child_process"); | ||
this._count = 0; | ||
this._limitReached = false; | ||
if (this._opts.heapdumpOnOOM) { | ||
require('bindings')('node_oom_heapdump_native.node').call(this._getHeapSnapshotPath(this._opts.path), this._opts.addTimestamp); | ||
if (options.OOMImplementation === "NATIVE_HOOK") { | ||
require('bindings')('node_oom_heapdump_native.node').call(this._getHeapSnapshotPath(this._opts.path), this._opts.addTimestamp); | ||
} else if (options.OOMImplementation === "GC_MONITORING") { | ||
this._monitorHeap(); | ||
} | ||
} | ||
} | ||
_monitorHeap() { | ||
// see https://www.npmjs.com/package/gc-stats | ||
let gcStats = new require('gc-stats')(); | ||
gcStats.on('stats', (stats) => { | ||
// gctype 2 is a Full GC (Mark/Sweep/Compact) | ||
if (stats.gctype === 2 && !this._busy) { | ||
let memoryUsagePercentage = Math.round((stats.after.usedHeapSize / stats.after.heapSizeLimit) * 100); | ||
if (memoryUsagePercentage > this._opts.threshold) { | ||
if (this._count < this._opts.limit) { | ||
// this is a full GC and the used heap size is using more than x% of the assigned heap space limit | ||
console.warn('OoM is imminent: Full GC (Mark/Sweep/Compact) complete and still more than %s% (%s%) of the heap is used. Creating heapdump now. GC stats: ', this._opts.threshold, Math.round(memoryUsagePercentage), JSON.stringify(stats)); | ||
this.createHeapSnapshot(this._opts.path, "OoM"); | ||
// block execution of other code for a while (5 second) to enable snapshot to be created | ||
const time = Date.now(); | ||
let diff = 0; | ||
do { | ||
diff = Date.now() - time; | ||
} | ||
while (diff < 5000); | ||
} else if (!this._limitReached) { | ||
this._limitReached = true; | ||
console.warn("OoM heapdump limit reached (%s); no more heapdumps will be created.", this._opts.limit); | ||
return; | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
/** | ||
@@ -70,3 +107,3 @@ * Calls the designated worker and returns a promise | ||
createHeapSnapshot(snapshotPath, logPrefix) { | ||
snapshotPath = this._getHeapSnapshotPath(snapshotPath); | ||
snapshotPath = this._getHeapSnapshotPath(snapshotPath, logPrefix); | ||
@@ -172,8 +209,16 @@ // start OoMworker to create heapdump | ||
* @param {String} snapshotPath | ||
* @param {String} logPrefix | ||
* @return {String} path | ||
*/ | ||
_getHeapSnapshotPath(snapshotPath) { | ||
_getHeapSnapshotPath(snapshotPath, logPrefix) { | ||
if (!snapshotPath) { | ||
snapshotPath = path.resolve(__dirname, "../heapsnapshot-" + Date.now()); | ||
} | ||
if (logPrefix === "OoM" && this._opts.addTimestamp) { | ||
if (snapshotPath.endsWith(".heapsnapshot")) { | ||
snapshotPath = snapshotPath.replace(".heapsnapshot", ""); | ||
} | ||
// in case of OoM error, add timestamp if needed | ||
snapshotPath += "-" + Date.now(); | ||
} | ||
if (!snapshotPath.endsWith(".heapsnapshot")) { | ||
@@ -180,0 +225,0 @@ snapshotPath += ".heapsnapshot"; |
{ | ||
"name": "node-oom-heapdump", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"description": "Create a V8 heap snapshot when an \"Out of Memory\" error occurs, or create a heap snapshot or CPU profile on request.", | ||
@@ -37,2 +37,3 @@ "main": "index.js", | ||
"chrome-remote-interface": "^0.25.5", | ||
"gc-stats": "^1.1.0", | ||
"nan": "^2.8.0", | ||
@@ -39,0 +40,0 @@ "require-main-filename": "^1.0.1", |
@@ -56,2 +56,4 @@ # node-oom-heapdump | ||
* heapdumpOnOOM - boolean whether to create a heapdump when an out of memory occurs. Default true. | ||
* OOMImplementation - Either "NATIVE_HOOK" or "GC_MONITORING". "NATIVE_HOOK" relies on the native v8 hook and makes sure that the heapdump is actually created when the OoM occurs. It's more impacted by the OoMKiller of Unix systems though, when being run in memory resticted environments like Docker. | ||
"GC_MONITORING" is the old implementation, which relies on GC monitoring. It's less impacted by OoMKiller, because the 'threshold' parameter determines when to create the heapdump. Use this option when you run into the OoMKiller of the Unix OS. Default is "NATIVE_HOOK". | ||
* path - the path where the heapdump ends up when an out of memory error occurs. '.heapsnapshot' is automatically appended. Defaults to this modules' directory. | ||
@@ -61,2 +63,6 @@ * addTimestamp - add a timestamp to the out of memory heapdump filename, to make it unique. Default is false. | ||
The following options are only relevant when OOMImplementation="GC_MONITORING". | ||
* limit - optionally, specify a limit to how many heapdumps will be created when being above the threshold. Default is 3. | ||
* threshold - integer between 0 and 100 (%) which determines when to make the heapdump. When the used heapSize exceeds the threshold, a heapdump is made. This value can be tuned depending on your configuration; if memory usage is very volatile, a lower value might make more sense. Default is 70. | ||
# API | ||
@@ -63,0 +69,0 @@ Besides creating heapdumps when an out of memory error occurs, there also is an API for creating heapdumps and CPU profiles on request. See below for the currently available API. |
@@ -6,2 +6,3 @@ let path = require('path'); | ||
heapdumpOnOOM: true, | ||
//OOMImplementation: "GC_MONITORING", // use the old implementation | ||
addTimestamp: false | ||
@@ -8,0 +9,0 @@ }); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31626
495
137
6
5
+ Addedgc-stats@^1.1.0
+ Addedgc-stats@1.4.1(transitive)
+ Addednode-gyp-build@4.8.3(transitive)