在大型 body 上改造 OOM
Retrofit OOM on large body
我正在使用改装发送相当大的文件,并且偶尔会遇到 OOM。方法:
@POST("/psm-service/model/{model}/video")
void sendVideo(@Header("X-Facebook-Access-Token") String token,
@Header("X-FB-Id") long fbId,
@Header("Content-Disposition") String contentDisposition,
@Path("model") long modelId,
@Body TypedOutput video,
Callback<Response> callback);
和服务:
RestAdapter adapter = new RestAdapter.Builder()
.setClient(new OkClient(Certification.getClient(this)))
.setEndpoint(Api.ENDPOINT)
.setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.BASIC : RestAdapter.LogLevel.NONE)
.build();
service = adapter.create(Api.ApiService.class);
客户端是一个带有自定义 SSL 的 OkHttpClient。我的 body 是一个使用 android 内容 URI 并设置长度、mimetype 和文件名的 TypedOutput。
@Override
public void writeTo(OutputStream out) throws IOException {
Utils.copyStream(getContentResolver().openInputStream(uri), out);
}
public static void copyStream(InputStream input, OutputStream output)
throws IOException
{
byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1)
{
output.write(buffer, 0, bytesRead);
}
}
据我了解,这应该以 1KB 的块发送我的 50 多 MB 文件。由于服务器限制,我必须传递文件大小。我试过完全关闭日志记录,但这没有用。
在其中一个较大的文件中,OOM 被抛入此方法。
java.lang.OutOfMemoryError: Failed to allocate a 120252388 byte allocation with 16777216 free bytes and 81MB until OOM
at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95)
at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:146)
at java.lang.StringBuffer.append(StringBuffer.java:219)
at com.splunk.mint.network.io.OutputStreamMonitor.updateBody(OutputStreamMonitor.java:67)
at com.splunk.mint.network.io.OutputStreamMonitor.write(OutputStreamMonitor.java:58)
at okio.Okio.write(Okio.java:78)
at okio.AsyncTimeout.write(AsyncTimeout.java:155)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:133)
at okio.RealBufferedSink.write(RealBufferedSink.java:45)
at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSink.write(HttpConnection.java:300)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:133)
at okio.RealBufferedSink.write(RealBufferedSink.java:148)
at lt.segfoltas.common.util.Utils.copyStream(Utils.java:51)
at lt.segfoltas.psm_casting.net.FormUploaderService$TypedStream.writeTo(FormUploaderService.java:565)
at retrofit.client.OkClient.writeTo(OkClient.java:88)
at com.squareup.okhttp.Call.getResponse(Call.java:237)
at com.squareup.okhttp.Call.execute(Call.java:84)
at retrofit.client.OkClient.execute(OkClient.java:53)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
at retrofit.RestAdapter$RestHandler.access0(RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler.obtainResponse(RestAdapter.java:278)
at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at retrofit.Platform$Android.run(Platform.java:142)
at java.lang.Thread.run(Thread.java:818)
编辑:
我对堆栈跟踪中的 bugsense 方法表示怀疑,所以我注释掉了 Mint.initAndStartSession
,现在我的堆甚至保持在 48MB,而之前是 200MB。虽然这解决了我的问题,但我想继续使用 bugsense。
显然 Splunk Mint 有 issues 和 OkHttp。禁用网络监控可解决此问题。
我正在使用改装发送相当大的文件,并且偶尔会遇到 OOM。方法:
@POST("/psm-service/model/{model}/video")
void sendVideo(@Header("X-Facebook-Access-Token") String token,
@Header("X-FB-Id") long fbId,
@Header("Content-Disposition") String contentDisposition,
@Path("model") long modelId,
@Body TypedOutput video,
Callback<Response> callback);
和服务:
RestAdapter adapter = new RestAdapter.Builder()
.setClient(new OkClient(Certification.getClient(this)))
.setEndpoint(Api.ENDPOINT)
.setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.BASIC : RestAdapter.LogLevel.NONE)
.build();
service = adapter.create(Api.ApiService.class);
客户端是一个带有自定义 SSL 的 OkHttpClient。我的 body 是一个使用 android 内容 URI 并设置长度、mimetype 和文件名的 TypedOutput。
@Override
public void writeTo(OutputStream out) throws IOException {
Utils.copyStream(getContentResolver().openInputStream(uri), out);
}
public static void copyStream(InputStream input, OutputStream output)
throws IOException
{
byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1)
{
output.write(buffer, 0, bytesRead);
}
}
据我了解,这应该以 1KB 的块发送我的 50 多 MB 文件。由于服务器限制,我必须传递文件大小。我试过完全关闭日志记录,但这没有用。
在其中一个较大的文件中,OOM 被抛入此方法。
java.lang.OutOfMemoryError: Failed to allocate a 120252388 byte allocation with 16777216 free bytes and 81MB until OOM
at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95)
at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:146)
at java.lang.StringBuffer.append(StringBuffer.java:219)
at com.splunk.mint.network.io.OutputStreamMonitor.updateBody(OutputStreamMonitor.java:67)
at com.splunk.mint.network.io.OutputStreamMonitor.write(OutputStreamMonitor.java:58)
at okio.Okio.write(Okio.java:78)
at okio.AsyncTimeout.write(AsyncTimeout.java:155)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:133)
at okio.RealBufferedSink.write(RealBufferedSink.java:45)
at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSink.write(HttpConnection.java:300)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:133)
at okio.RealBufferedSink.write(RealBufferedSink.java:148)
at lt.segfoltas.common.util.Utils.copyStream(Utils.java:51)
at lt.segfoltas.psm_casting.net.FormUploaderService$TypedStream.writeTo(FormUploaderService.java:565)
at retrofit.client.OkClient.writeTo(OkClient.java:88)
at com.squareup.okhttp.Call.getResponse(Call.java:237)
at com.squareup.okhttp.Call.execute(Call.java:84)
at retrofit.client.OkClient.execute(OkClient.java:53)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
at retrofit.RestAdapter$RestHandler.access0(RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler.obtainResponse(RestAdapter.java:278)
at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at retrofit.Platform$Android.run(Platform.java:142)
at java.lang.Thread.run(Thread.java:818)
编辑:
我对堆栈跟踪中的 bugsense 方法表示怀疑,所以我注释掉了 Mint.initAndStartSession
,现在我的堆甚至保持在 48MB,而之前是 200MB。虽然这解决了我的问题,但我想继续使用 bugsense。
显然 Splunk Mint 有 issues 和 OkHttp。禁用网络监控可解决此问题。