文件下载接口在 2GB 的对象上必现 OOM,堆日志里是一次 2GB 的 byte 数组分配失败,其他接口正常。小文件下载没有问题。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,代码把对象整体读进内存再写响应,峰值内存等于文件大小乘以并发数。几个大文件同时下载,堆直接见底。流式复制的缓冲区只有几十 KB,差别全在是否边读边写。
「大文件下载内存溢出」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
try (InputStream in = s3.getObject(req).getObjectContent();
OutputStream out = response.getOutputStream()) {
in.transferTo(out);
}
权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
具体做法是,用输入流对接输出流 别先转成 byte 数组;缓冲区给 32KB 到 64KB 就够;响应提交后不要再补设响应头;限制单机并发下载数 避免带宽和堆同时被占满。
最后用这个标准收尾,下载 2GB 文件时堆曲线平稳,接口完整返回且文件 MD5 一致。
