使用Buffer.from()上传大视频至S3引发内存泄漏的解决方法
解决大视频转存S3时Buffer.from()导致的内存溢出与泄漏问题
你的问题核心在于手动通过fileReadStream.push(Buffer.from(nextChunk))处理流数据时,没有正确处理流背压,且重复创建Buffer导致内存无法及时回收。下面是具体的解决方案,完全保留流管道的同时解决内存问题:
1. 用Transform流替代手动push操作
Node.js的stream.Transform是专门用于在流管道中修改数据的内置模块,它会自动处理背压(当下游S3上传速度慢时,上游会暂停读取,避免内存堆积),而且不需要手动管理Buffer的push逻辑。
示例代码:
const { Transform } = require('stream'); const AWS = require('aws-sdk'); const fs = require('fs'); const s3 = new AWS.S3(); // 创建自定义Transform流处理数据 const modifyStream = new Transform({ transform(chunk, encoding, callback) { // 在这里实现你对chunk的修改逻辑(替代原nextChunk的处理) const modifiedChunk = chunk; // 替换为你的实际修改操作,比如加密、格式转换等 // 若必须创建新Buffer,仅在必要时执行,直接通过callback传递结果 // 示例:const modifiedChunk = Buffer.from(chunk.toString('utf8').replace('old', 'new'), 'utf8'); callback(null, modifiedChunk); } }); // 构建完整流管道:文件读取 → 数据修改 → S3上传 const fileReadStream = fs.createReadStream('/path/to/large-video.mp4'); const uploadPromise = s3.upload({ Bucket: 'your-target-bucket', Key: 'stored-video.mp4', Body: modifyStream }).promise(); fileReadStream.pipe(modifyStream); // 处理流事件,确保资源及时回收 fileReadStream.on('error', (err) => { console.error('文件读取失败:', err); modifyStream.destroy(err); }); modifyStream.on('error', (err) => { console.error('数据修改失败:', err); fileReadStream.destroy(err); }); uploadPromise.then(() => { console.log('视频转存S3完成'); }).catch((err) => { console.error('S3上传失败:', err); // 主动销毁所有流释放内存 fileReadStream.destroy(); modifyStream.destroy(); });
2. 避免不必要的Buffer复制
- 如果
nextChunk本身就是Buffer类型,直接使用原对象,不要调用Buffer.from()(这会创建新的Buffer实例,占用额外内存)。 - 如果
nextChunk是字符串,明确指定编码(比如Buffer.from(nextChunk, 'utf8')),避免默认编码导致的隐式转换开销。
3. 确保流的正确销毁与资源回收
- 所有流都要监听
error事件,一旦出错立即调用destroy()销毁流,防止资源泄漏。 - 上传完成或出错后,手动销毁未自动关闭的流(比如文件读取流),确保内存及时释放。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

