okhttp上传文件出现OOM

okhttp是一个比较优秀的库,使用非常广泛,相信大家都比较熟悉。在最近的使用中却发现了一个OOM的情况,在上传比较大的图片或视频时会发生,日志如下

Caused by: java.lang.OutOfMemoryerror: Failed to alocate a 267201798 byte alcation with 8388608 free bytes and 233MB until OOM
at java.lang.StringFactory.newStringFromBytes(StringFactory.java:79)
at java.lang.StringFactory.newStringFromBytes(StringFactory,java:207)
at okio.Buffer.readString(Buffer.java:713)
at okio.Buffer.readString(Buffer.java:696)
at okhtpp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:200)
…………

看日志是okhttp日志库的锅。HttpLoggingInterceptor是okhttp提供的一个日志库,代码比较简单,原理也是使用了拦截器来打印请求头请求体以及请求结果。来看一下出现OOM的地方

…………    
if (isPlaintext(buffer)) {
    logger.log(buffer.readString(charset));
    logger.log("--> END " + request.method()
        + " (" + requestBody.contentLength() + "-byte body)");
} else {
    logger.log("--> END " + request.method() + " (binary "
    + requestBody.contentLength() + "-byte body omitted)");
}
…………

如果打印基本是body而且有请求体就会打印请求体,其中isPlaintext用来判断是否可以打印body内容,然后使用Okio的Buffer来构建一个String并打印,当body太大时,需要构建内存会非常大,导致了OOM的发生。isPlaintext没有判断body是否包含文件信息(文件内容打印也没有意义),而且没有判断buffer是否过长 。

可以使用只打印HEADER来避免这种情况:

interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

或者复制一遍日志来修改代码,只打印一定长度的日志。

发布了53 篇原创文章 · 获赞 17 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/jklwan/article/details/101002449