添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

I am using OkHttp 3, and I keep getting leaked connection warnings:

WARNING: A connection to https://help.helpling.com/ was leaked. Did you forget to close a response body?
Jul 14, 2016 6:57:09 PM okhttp3.ConnectionPool pruneAndGetAllocationCount

Everytime I get a ResponseBody, I either call .string() which supposedly closes the stream for me, or I explicitly close it in a finally block, in the following way:

ResponseBody responseBody = response.body();
try (Reader responseReader = responseBody.charStream()) {
finally {
    responseBody.close();

My application makes intense use of the network, and yet that warning appears frequently. I never observed any problem caused by this presumed leak, but I would still like to understand if and what I am doing wrong.

Could anyone shed some light on this?

By upgrading to OkHttp 3.7, Eclipse started warning me of potential resource leaks. I found my problem to be in this method I wrote:

public static Response getResponse(HttpUrl url, OkHttpClient client) throws IOException {
    Builder request = new Request.Builder().url(url);
    Response response = client.newCall(request.build()).execute();
    if (!response.isSuccessful()) {
        boolean repeatRequest = handleHttpError(response);
        if (repeatRequest)
            return getResponse(url, client, etag);
            throw new IOException(String.format("Cannot get successful response for url %s", url));
    return response;

I assumed that by always calling getResponse(url, client).body().string() the stream would close automatically. But, whenever a response was unsuccessful, an exception would raise before the execution of .string(), thus the stream would remain open.

Adding an explicit close in case of unsuccessful response solved the problem.

if (!response.isSuccessful()) {
    boolean repeatRequest = handleHttpError(response);
    response.close();
  

Some evil code may steal your lock (very popular this one, also has an "accidentally" variant)

I'm more worried about accidentally. What it amounts to is that this use of this is part of your class' exposed interface, and should be documented. Sometimes the ability of other code to use your lock is desired. This is true of things like Collections.synchronizedMap (see the javadoc).

All synchronized methods within the same class use the exact same lock, which reduces throughput

This is overly simplistic thinking; just getting rid of synchronized(this) won't solve the problem. Proper synchronization for throughput will take more thought.

You are (unnecessarily) exposing too much information

This is a variant of #1. Use of synchronized(this) is part of your interface. If you don't want/need this exposed, don't do it.

You're trying to show a Dialog after you've exited an Activity.

[EDIT]

This question is one of the top search on google for android developer, therefore Adding few important points from comments, which might be more helpful for future investigator without going in depth of comment conversation.

Answer 1 :

You're trying to show a Dialog after you've exited an Activity.

Answer 2

This error can be a little misleading in some circumstances (although the answer is still completely accurate) - i.e. in my case an unhandled Exception was thrown in an AsyncTask, which caused the Activity to shutdown, then an open progressdialog caused this Exception.. so the 'real' exception was a little earlier in the log

Answer 3

Call dismiss() on the Dialog instance you created before exiting your Activity, e.g. in onPause() or onDestroy()

Related Question