我正在调试Android应用中的问题。我发现根本原因是文件描述符超出了限制。经过进一步调查后,我发现应用程序的插槽太多了。我使用OkHttpClient 2.5进行所有网络通信,因此我想知道如何限制连接池大小。以下是我的代码段:
OkHttpClient okHttpClient = new OkHttpClient().setConnectTimeout(TIMEOUT);
ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS,
KEEP_ALIVE_DURATION_MS);
okHttpClient.set(connectionPool);
@RequireArgsConstructor
public HttpEngineCallable implements Callable<IHttpResponse>
{
private final String url;
public IHttpResponse call () throws Exception
{
try
{
Request request = Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
Response rawResponse = call.execute();
return new OkHttpResponse(rawResponse);
}
catch (Exception e)
{
throw new IllegalStateException(e);
}
}
private final Function<IHttpResponse, T> httpResponseParser = new Function<IHttpResponse, T>()
{
@Nullable
@Override
public T apply(@Nullable IHttpResponse httpResponse)
{
if(httpResponse == null)
{
return null;
}
InputStream stream = httpResponse.getBody();
JsonParser parser = null;
T result = null;
try
{
parser = jsonFactory.createParser(stream);
result = strategy.parseData(parser);
}
catch (Exception e)
{
log.error("Unable to convert {} with {}.", stream, strategy, e);
}
finally
{
IOUtils.closeQuietly(parser);
IOUtils.closeQuietly(stream);
}
return result;
}
};
Future<T> future = executorService.submit(new HttpEngineCallable(url));
Future<V> finalFuture = Futures.transform(future, httpResponseParser, executorService);
T result = timeoutExecutorService.submit(new Runnable()
{
try
{
T result = finalFuture.get(CLIENT_TIMEOUT, TIMEUNIT)
if (result == null)
{
notify onFailure listeners
}
else
{
notify onSuccess Listeners
}
}
catch(Exception ex)
{
notify onFailure listeners
}
}
所以我对这个实现有几个问题:
finalFuture.get(CLINT_TIMEOUT, TIMEUNIT)
抛出超时异常,那么解析器函数中的finally块是否仍会被执行?我指望它关闭我的联系。 答案 0 :(得分:6)
我们遇到了类似的问题,有太多打开的文件描述符导致我们的应用程序崩溃。
问题是我们为每个请求创建了一个OkHttpClient。默认情况下,每个OkHttpClient都附带自己的连接池,这当然会破坏连接/线程/文件句柄的数量,并阻止在池中正确重用。
我们通过在单例中手动创建全局ConnectionPool ,然后将其传递给构建实际OkHttpClient的OkHttpClient.Builder对象来解决问题。
...
builder.connectionPool(GLOBAL_CONNECTION_POOL);
OkHttpClient client = builder.build();
...
这仍允许使用OkHttpClient.Builder
进行每请求配置,并确保所有OkHttpClient
实例仍在使用公共连接池。
然后我们能够正确调整全局连接池的大小。