加速 JavaScript ArrayBuffer 内存释放
JavaScript 的垃圾回收机制能自动管理内存,但持续处理大型 ArrayBuffer(每秒几 MB)会导致卡顿。在 Chrome 等浏览器中,内存占用会飙升到数百 MB,尤其在视频流处理场景下。Firefox 处理得更好,但仍会出现峰值激增。这对 32 位进程和 RAM 有限的移动设备尤为关键。
ArrayBuffer 专为二进制数据设计,但缺少手动释放或调整大小的方法。像 ArrayBuffer.transfer() 这样的提案尚未广泛支持。缓冲区进入分离状态(byteLength=0,访问抛出 TypeError)后,垃圾回收器能快速回收它。
MessageChannel 技巧分离 ArrayBuffer
MessageChannel 可在不同上下文中传输数据。关闭 port2 会分离 port1:数据直接进入垃圾回收,而无需等待事件循环。
const GarbageBin = (() => {
/** @type {MessageChannel | null} */
let messageChannel = null;
/**
* 加速 ArrayBuffer、TypedArray、DataView 的内存释放。
* @param {any} junk
*/
function dispose(junk) {
if (typeof junk === 'object' && junk) {
const buffer = junk.buffer || junk;
if (buffer.byteLength) {
if (!messageChannel) {
messageChannel = new MessageChannel();
messageChannel.port2.close();
}
messageChannel.port1.postMessage(buffer, [buffer]);
}
}
}
return { dispose };
})();
使用示例:
let buffer = new ArrayBuffer(1_000_000);
// 处理 buffer...
GarbageBin.dispose(buffer);
buffer = null;
兼容性: Chrome 55+、Firefox 50+ 可用。Chrome 56 版本数据残留问题。实际场景下峰值内存减少 100 MB。
限制: 不适用于 asm.js 堆(Firefox 49)。跨版本不稳定。
Worker 技巧批量释放内存
Worker.postMessage 会分离 ArrayBuffer。终止 worker(self.close())能立即释放线程所有内存。
优化:累积约 10 MB 后再关闭,以减少创建/销毁开销。
const GarbageBin = (() => {
const BIN_CAPACITY = 10_000_000;
/** @type {Worker | null} */
let worker = null;
let workerURL = '';
let bytesInWorker = 0;
function dispose(junk) {
if (typeof junk === 'object' && junk) {
const buffer = junk.buffer || junk;
if (buffer.byteLength) {
if (!worker) {
if (!workerURL) {
workerURL = URL.createObjectURL(new Blob([
`'use strict'; self.onmessage = ({data}) => { if (!data) self.close(); };`
], {type: 'application/javascript'}));
}
worker = new Worker(workerURL, {name: 'GarbageBin'});
}
bytesInWorker += buffer.byteLength;
worker.postMessage(buffer, [buffer]);
if (bytesInWorker > BIN_CAPACITY) {
clear();
}
}
}
}
function clear() {
if (worker) {
worker.postMessage(null);
worker = null;
bytesInWorker = 0;
}
}
return { dispose, clear };
})();
关闭时调用 GarbageBin.clear()。结果:Chrome 峰值减少 310 MB,Firefox 减少 70 MB。
问题: Firefox 55+ 存在虚拟地址空间泄漏。
性能对比与建议
测试时长 40 分钟:CPU 占用在误差范围内。Firefox 中 MessageChannel 比 Worker 慢(合成测试)。
| 技巧 | Chrome 效果 | Firefox 效果 | 兼容性 |
|---------------|-------------|--------------|-----------------|
| MessageChannel | -100 MB | 稳定 | 较低 |
| Worker | -310 MB | -70 MB | 较高(Firefox 55+ 除外)|
- 生产环境首选 Worker:更可靠,Chrome 效果更显著。
- 在目标浏览器中测试:垃圾回收算法在演进。
- 避免用于 asm.js/WebAssembly 堆。
- 用 perfmon/进程资源监视器监控工作集。
Worker 在高负载(如视频、流)下表现突出。
关键要点
- 两种技巧均通过 postMessage 分离 ArrayBuffer,加速垃圾回收。
- Worker 批量处理 10 MB 以降低开销。
- 效果:Chrome 流媒体峰值减少高达 310 MB。
- CPU 开销 <1%(实际场景)。
- 测试兼容性:垃圾回收变更会导致技巧失效。
— Editorial Team
暂无评论。