web-dev-qa-db-ja.com

OkHttp:接続漏れの警告を避ける

私はOkHttp 3を使用していますが、接続警告が漏れ続けています:

_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
_

ResponseBodyを取得するたびに、次の方法で.string()を呼び出して、おそらくストリームを閉じます。または、finallyブロックで明示的に閉じます。

_ResponseBody responseBody = response.body();
try (Reader responseReader = responseBody.charStream()) {
    ...
}
finally {
    responseBody.close();
}
_

私のアプリケーションはネットワークを多用していますが、その警告は頻繁に表示されます。この推定リークによって引き起こされる問題は一度も見たことがありませんが、まだifおよびwhat間違っていることを理解したいと思います。

誰もこれに光を当てることができますか?

27
Alphaaa

OkHttp 3.7にアップグレードすることで、Eclipseは潜在的なリソースリークの警告を開始しました。私が書いたこの方法に問題があることがわかりました:

_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;
}
_

常にgetResponse(url, client).body().string()を呼び出すことで、ストリームが自動的に閉じると想定しました。ただし、応答が失敗すると、.string()の実行前に例外が発生するため、ストリームは開いたままになります。

応答が失敗した場合に明示的なクローズを追加すると、問題が解決しました。

_if (!response.isSuccessful()) {
    boolean repeatRequest = handleHttpError(response);
    response.close();
}
_
12
Alphaaa

他の回答で述べたように、応答を閉じる必要があります。少し簡潔な方法は、tryブロックでResponseBodyを宣言して、自動的に閉じるようにすることです。

try(ResponseBody body = ....){
....
}
10