我们正在做一个实验,需要获取一组函数的内存使用情况。我们最初的做法是在函数调用之前和之后使用 process.memoryUsage().heapUsed ,然后使用差异作为我们的衡量标准。然而,底层的垃圾收集器似乎使这种方法不可行且不可靠。有时我们会得到负值,这是 gc 所期望的,但我们从减法中得到的值范围很大,使得这种方法的正确性不可靠。
// Code example of our inital approach
const memoryBefore = process.memoryUsage().heapUsed
const result = await f1()
const memoryAfter = process.memoryUsage().heapUsed
console.log("MEMORY USAGE:", memoryBefore - memoryAfter)
我们如何改变我们的方法来更好地捕获和计算内存使用情况?我们已经研究了设置 --expose-gc 和 --trace-gc 来显式调用垃圾收集器,并使用跟踪从输出的值计算内存使用情况(在这个问题中找到)。
gc()
的问题在于,垃圾收集器并不总是在 gc() 调用时激活,并且不一致。
// Child process
import { setFlagsFromString } from 'v8'
setFlagsFromString('--expose-gc --trace-gc')
function f1() {
for (let i = 0; i < 1000; i++) new Array(1000)
console.log('Ran f1')
}
process.on('message', (msg) => {
const start = process.memoryUsage().heapUsed
global.gc?.()
console.log('>>> START')
f1()
console.log('>>> END\n')
const end = process.memoryUsage().heapUsed
global.gc?.()
})
运行上面代码示例中的代码,产生下面的跟踪
[29840:0000020ED48B8010] 870 ms: Scavenge 100.5 (120.4) -> 95.0 (124.9) MB, 2.87 / 0.00 ms (average mu = 1.000, current mu = 1.000) task;
[29840:0000020ED48B8010] 891 ms: Mark-Compact 95.0 (124.9) -> 92.2 (128.9) MB, 1.91 / 0.00 ms (+ 17.6 ms in 259 steps since start of marking, biggest step 0.1 ms, walltime since start of marking 20 ms) (average mu = 0.973, current mu = 0.973) finalize incremental marking via task; GC in old space requested
>>> START
Ran f1
>>> END
>>> START
[29840:0000020ED48B8010] 2004 ms: Scavenge 108.0 (128.9) -> 92.3 (128.9) MB, 0.49 / 0.00 ms (average mu = 0.973, current mu = 0.973) allocation failure;
Ran f1
>>> END
>>> START
Ran f1
>>> END
>>> START
Ran f1
>>> END
>>> START
Ran f1
>>> END
>>> START
Ran f1
>>> END
>>> START
Ran f1
>>> END
似乎很少或没有与我们的问题类似的相关问题,因此我们将不胜感激。
GC 将释放分配的实例在很大程度上是不可预测的。这使得任何密切关注总体内存使用情况并据此进行测量的方法都不可靠。
这是您可以在 Linux 中使用的方法:
准备两个应用程序 - 一个具有预期功能,另一个是空的。
一次运行一个应用程序。
获取进程运行时的PID,运行以下命令即可获取该进程的内存使用峰值。
$ grep ^VmPeak /proc/113/status
区别在于函数的内存使用情况