Reputation: 4316
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?
Upvotes: 44
Views: 46213
Reputation: 60
Even with success, I need to close the response for me. And body().string() did not close the connection. So explicitly we need to close the connection even if the response is 200 OK. So better put it in finally {... } block.
try{
response = client.newCall(request).execute();
if (HttpStatus.valueOf(response.code()).is2xxSuccessful()) {
try (ResponseBody body = response.peekBody(Long.MAX_VALUE)) {
Identifier identifier = objectMapper.readValue(body.string(), Identifier.class);
// response.close();
return identifier;
} catch (RuntimeException e) {
// response.close();
throw new SomeException( .....);
}
} else {
// response.close();
throw new SomeException(...);
} ...
} catch(RuntimeException ex){
.......
}
finally {
if (response != null) {
response.close();
}
}
Upvotes: 0
Reputation: 4316
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);
else
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();
}
Upvotes: 28
Reputation: 161
As mentioned in the other answers, you have to close the response. A slightly cleaner approach would be to declare the ResponseBody
in the try block, so that it will be automatically closed.
try(ResponseBody body = ....){
....
}
Upvotes: 16