You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何blob.arrayBuffer占用的内存无法自动释放?

Node.js中Blob.arrayBuffer()引发内存无法释放的问题

我编写了一段将客户端摄像头输入录制到服务器的代码:

async function saveIntoMp4(chunks) {
    const options = {
        type: "video/webm"
    }
    let blob = new Blob(chunks, options);
    chunks.length = 0 // 防止内存泄漏
    const buffer = Buffer.from(await blob.arrayBuffer());
    try {
        fs.writeFile(
            `./videos/1.mp4`,
            buffer,
            () => console.log("video is saved!")
        );
    } catch (error) {
        console.log(error)
    }
}

但在Ubuntu 20.04.6 LTS系统中,每次调用该函数内存占用都会持续增加,buffer占用的内存始终无法释放。我未保留buffer、chunks、blob等对象的引用,使用Node.js 18.9和20版本均未解决问题,请问为何blob.arrayBuffer()无法释放占用的内存?


可能的原因及解决方案

1. 异步写入导致Buffer被闭包长期持有

你使用的是异步版fs.writeFile,在回调函数执行完成前,buffer会被闭包引用,无法被垃圾回收(GC)。如果录制频率较高,大量未回收的Buffer会堆积在内存中,导致占用持续上升。

解决办法:改用同步写入或Promise版写入,并显式解除引用:

// 方案1:同步写入
try {
    fs.writeFileSync(`./videos/1.mp4`, buffer);
    console.log("video is saved!");
} catch (error) {
    console.log(error);
}

// 方案2:Promise版异步写入+显式置空
try {
    await fs.promises.writeFile(`./videos/1.mp4`, buffer);
    console.log("video is saved!");
    buffer = null; // 主动解除引用,帮助GC回收
} catch (error) {
    console.log(error);
}

2. Blob转Buffer产生冗余内存拷贝

Node.js中,Blob.arrayBuffer()会创建一份内存拷贝,之后Buffer.from()又会创建第二份拷贝。这两份拷贝可能因GC标记延迟无法及时回收,尤其在处理大视频片段时更明显。

解决办法:跳过Blob环节,直接将chunks合并为Buffer,避免中间拷贝:

async function saveIntoMp4(chunks) {
    // 直接将chunks(假设为Uint8Array数组)合并为Buffer
    const buffer = Buffer.concat(chunks.map(chunk => Buffer.from(chunk)));
    chunks.length = 0; // 清空原数组
    try {
        await fs.promises.writeFile(`./videos/1.mp4`, buffer);
        console.log("video is saved!");
        buffer = null;
    } catch (error) {
        console.log(error);
    }
}

3. Linux系统内存缓存的误导

Ubuntu系统默认会将空闲内存用作文件缓存,top或htop显示的高内存占用可能包含缓存部分,并非真正的内存泄漏。可以用free -h命令查看实际占用:

free -h

输出中used列排除buff/cache后的数值才是进程实际占用的内存。如果确认是内存泄漏,可通过Node.js调试工具排查:

node --inspect your-app.js

打开Chrome浏览器访问chrome://inspect,连接到Node进程后,在Memory面板生成多次函数调用后的堆快照,对比快照找到未被回收的对象。

4. 重复写入同一文件的潜在问题

每次都写入./videos/1.mp4,若文件被其他进程锁定(比如前一次写入未完成、文件被打开查看),可能导致相关内存资源无法释放。可以尝试使用唯一文件名测试:

const filename = `./videos/${Date.now()}.mp4`;
await fs.promises.writeFile(filename, buffer);

内容的提问来源于stack exchange,提问作者Hypothesis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 05:07:33