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

上传100MB视频文件到服务器时出现OutOfMemoryError该如何修复?

问题根本原因
  • 核心问题大概率是contentLength()方法实现错误:如果该方法没有直接调用file.length()获取本地文件长度,而是手动读取文件内容计算大小,那么每次循环调用都会重新加载一次文件内容,循环几百次就会把内存占满。小文件因为加载耗时短、占用内存低,不容易触发阈值,大文件就会直接OOM。
  • 其次是Okio Buffer使用逻辑存在隐患:部分Okio版本中调用sink.write(buffer, readCount)不会自动清理Buffer中已写出的内容,会导致Buffer持续累积读取到的文件数据,最终内存溢出。
  • 额外隐患:原代码中try-with-resources仅管理了Buffer的生命周期,Source的关闭逻辑放在finally里,出现极端异常时可能出现资源泄漏,加重内存负担。
修复方案

首先确认contentLength()直接返回文件原生长度,不要做读取文件内容的操作,示例实现:

@Override
public long contentLength() {
    return file.length();
}

然后修改writeTo逻辑,提前获取文件长度、优化Buffer管理,修复后代码如下:

@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
    // 提前一次性获取文件总长度,避免循环内重复调用
    long originalFileLength = contentLength();
    long remaining = originalFileLength;
    // 用try-with-resources统一管理Source和Buffer,自动释放资源
    try (Source source = Okio.source(file);
         Buffer buffer = new Buffer()) {
        for (long readCount; (readCount = source.read(buffer, DEFAULT_BUFFER_SIZE)) != -1; ) {
            if (mMediaUploadService.isRetryShown())
                break;
            sink.write(buffer, readCount);
            // 主动清理Buffer中已写出的内容,避免内存累积
            buffer.clear();
            sink.flush();
            remaining -= readCount;
            remainingBytes = remaining;
            LogMessage.d(TAG, "source size: " + originalFileLength + " remaining bytes: " + remainingBytes);

            uploadTaskCompletedListener.onUploadProgressChanged(readCount, originalFileLength);
        }
        firstTimeCall[0] = true;
    } catch (Exception e) {
        LogMessage.e(TAG, "write to exception: = " + e.getMessage());
    }
}

如果要进一步简化逻辑,可以直接使用Okio自带的BufferedSource实现,不需要手动操作Buffer:

@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
    long originalFileLength = contentLength();
    try (BufferedSource source = Okio.buffer(Okio.source(file))) {
        long readCount;
        byte[] tempBuffer = new byte[DEFAULT_BUFFER_SIZE];
        while ((readCount = source.read(tempBuffer)) != -1) {
            if (mMediaUploadService.isRetryShown())
                break;
            sink.write(tempBuffer, 0, (int) readCount);
            sink.flush();
            uploadTaskCompletedListener.onUploadProgressChanged(readCount, originalFileLength);
        }
        firstTimeCall[0] = true;
    } catch (Exception e) {
        LogMessage.e(TAG, "write to exception: = " + e.getMessage());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:57:03