OkHttp:连接池和文件句柄

时间:2017-03-22 10:30:57

标签: threadpool file-descriptor okhttp3 filehandle okhttp

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

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

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

我们能够准确地调试这一点,其中每个使用.enqueue()进行的异步调用将导致打开文件句柄增加3。

问题是,OkHttp中的ConnectionPool似乎将连接线程保持的时间比实际需要的时间长得多。 (This post谈了五分钟,虽然我没有在任何地方看到这个。)

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

我已经看到可以使用Dispatcher.setMaxRequests()限制并行呼叫的数量(尽管似乎不清楚这是否真的有效,请参阅here) - 但这仍然无法解决打开线程和文件句柄堆积的问题。

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

1 个答案:

答案 0 :(得分:6)

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

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

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

我们的解决方案

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

  • 这仍允许使用OkHttpClient
  • 进行按请求配置
  • 确保所有OkHttpClient.Builder实例仍在使用公共连接池。

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