const { createCanvas } = require('canvas');
function renderImage() {
const bgCanvas = createCanvas(800, 600);
let bgCtx = bgCanvas.getContext('2d');
bgCtx = null;
global.gc();
}
console.log('Memory usage before:', process.memoryUsage());
renderImage()
console.log('Memory usage after:', process.memoryUsage());
上面的代码是我的不和谐机器人中可能存在内存泄漏的最小代码示例。它似乎通过 .getContext() 方法使用了 20-40mb 的内存,并且没有将其返还。任何见解将不胜感激,因为我完全迷失在这里。
我正在使用画布^2.11.2
这是内存日志:
Memory usage before: {
rss: 35856384,
heapTotal: 4665344,
heapUsed: 4369736,
external: 1323854,
arrayBuffers: 10515
}
Memory usage after: {
rss: 63238144,
heapTotal: 5976064,
heapUsed: 3500384,
external: 1455306,
arrayBuffers: 10475
}
所以,我做了一些研究和一些测试,希望这些信息对您有帮助:
首先,您正确使用该库 - 对象引用不会保存,因此它们将被垃圾收集器收集。
现在,关于
Canvas
库:
getContext
调用将上下文添加到父Canvas
对象,但这仅在尚未创建上下文对象时第一次调用该函数时发生 - 对getContext
的后续调用使用已创建的对象,因此不耗费内存。我附上canvas
库源代码中的函数代码:
Canvas.prototype.getContext = function (contextType, contextAttributes) {
if (contextType == '2d') {
const ctx = this._context2d || (this._context2d = new Context2d(this, contextAttributes))
this.context = ctx
ctx.canvas = this
return ctx
}
}
“Canvas”库的大部分代码是用 C++ 编写的,没有垃圾收集器,并且内存管理是手动完成的,因此那里可能隐藏着轻微的泄漏。如果应用程序运行后内存泄漏仍然存在(我在测试中没有遇到这种情况) - 在 canvas github 存储库上创建问题是有意义的。
关于GC(垃圾收集器)
总结一下 - V8 垃圾收集器是一个复杂的机制,它不会在删除对象引用后立即释放内存,所以:
global.gc()
,在自动模式下效果很好在正在运行且不处于“空闲”模式的正在运行的应用程序上运行测试
我的测试结果(测试代码)
Application started, RSS usage: 44.19584mbs
... (Canvas objects created)
RSS usage: 108.650496mbs, time since start: 2.5 minutes
... (Released a part of memory)
RSS usage: 79.773696mbs, time since start: 2.6 minutes
... (Released a part of memory)
RSS usage: 55.11168mbs, time since start: 32.3 minutes
... (Back to the original memory value)
RSS usage: 46.116864mbs, time since start: 63.4 minutes
使用
--trace-gc
标志运行代码,例如用于跟踪 GC 操作的 node --trace-gc index.js