OkHttp:连接池和文件句柄

fgy*_*ica 5 file-descriptor filehandle threadpool okhttp okhttp3

我们对来自Android应用程序的所有网络流量使用Retrofit/OkHttp3.到目前为止,一切似乎都很顺利.

但是,我们现在偶尔会让我们的应用程序/进程耗尽文件句柄.

  • Android允许每个进程最多1024个文件句柄
  • OkHttp将为每个异步调用创建一个新线程
  • 以这种方式创建的每个线程将(从我们的观察)负责3个新文件句柄(2个管道和一个套接字).

我们能够准确地调试它,每次调度异步调用.enqueue()将导致打开文件句柄增加3.

问题是,ConnectionPoolOkHttp中的连接线程似乎比实际需要的时间长得多.(这篇文章谈了五分钟,虽然我没有看到这个指定的任何地方.)

  • 这意味着如果您快速调度请求,连接池的大小将会增加,文件句柄数量也会增加 - 直到达到应用程序崩溃的1024.

我已经看到有可能限制并行调用的数量Dispatcher.setMaxRequests()(尽管似乎不清楚这是否真的有效,请参见此处) - 但这仍然无法解决开放线程和文件句柄堆积的问题.

我们怎么能阻止OkHttp创建太多文件句柄?

fgy*_*ica 7

我在这里回答我自己的问题,以记录我们遇到的这个问题.我们花了一段时间来解决这个问题,我认为其他人也可能会遇到这种情况,并且可能对此答案感到高兴.


我们的问题是我们为OkHttpClient 每个请求创建了一个,因为我们使用它的构建器/拦截器API来配置一些每个请求参数,如HTTP头或超时.

默认情况下,每个都有OkHttpClient自己的连接池,这当然会耗尽连接/线程/文件句柄的数量,并阻止在池中正确重用.

我们的方案

我们通过ConnectionPool在单例中手动创建全局,然后将其传递给OkHttpClient.Builder构建实际的对象来解决问题OkHttpClient.

  • 这仍然允许使用的每请求配置 OkHttpClient.Builder
  • 确保所有OkHttpClient实例仍在使用公共连接池.

我们能够正确调整全局连接池的大小.