Hi,
I am using Retrofit 2.0.0.
OkHttp 3.1.2.
Some of my users are getting the following exception:
java.net.SocketException: socket failed: EMFILE (Too many open files)
at libcore.io.IoBridge.socket(IoBridge.java:619) ~[na:0.0]
at java.net.PlainSocketImpl.create(PlainSocketImpl.java:198) ~[na:0.0]
at java.net.Socket.checkOpenAndCreate(Socket.java:689) ~[na:0.0]
at java.net.Socket.setSoTimeout(Socket.java:543) ~[na:0.0]
at com.android.org.conscrypt.OpenSSLSocketImpl.setSoTimeout(OpenSSLSocketImpl.java:1140) ~[na:0.0]
at com.android.org.conscrypt.OpenSSLSocketImplWrapper.setSoTimeout(OpenSSLSocketImplWrapper.java:111) ~[na:0.0]
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:155) ~[na:0.0]
at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111) ~[na:0.0]
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188) ~[na:0.0]
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127) ~[na:0.0]
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) ~[na:0.0]
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289) ~[na:0.0]
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241) ~[na:0.0]
at okhttp3.RealCall.getResponse(RealCall.java:240) ~[na:0.0]
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198) ~[na:0.0]
When i look at crashlytics i see a lot of threads which are running:
at com.android.org.conscrypt.NativeCrypto.SSL_read(NativeCrypto.java)
at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:811)
at okio.Okio$2.read(Okio.java:139)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
at okio.RealBufferedSource.request(RealBufferedSource.java:71)
at okio.RealBufferedSource.require(RealBufferedSource.java:64)
at okio.RealBufferedSource.readInt(RealBufferedSource.java:232)
at okhttp3.internal.framed.Spdy3$Reader.nextFrame(Spdy3.java:129)
at okhttp3.internal.framed.FramedConnection$Reader.execute(FramedConnection.java:600)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.lang.Thread.run(Thread.java:818)
I am initiating Okhttp only once in my app this way:
`OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.connectTimeout(3 * 1000, TimeUnit.MILLISECONDS);
clientBuilder.readTimeout(25 * 1000, TimeUnit.MILLISECONDS);
File cacheDir = new File(mWeakContext.get().getFilesDir().getAbsolutePath(), "http-cache");
Cache cache = new Cache(cacheDir, 16 * 1024 * 1024); // 16MB
clientBuilder.cache(cache);
// set proxy
Properties properties = System.getProperties();
if (properties.containsKey("https.proxyHost")) {
String proxyHost = properties.getProperty("https.proxyHost");
int proxyPort = Integer.parseInt(properties.getProperty("https.proxyPort"));
clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
proxyHost,
proxyPort)
));
}
clientBuilder.addInterceptor(mHeadersInterceptor);
clientBuilder.addInterceptor(mSignInterceptor);
clientBuilder.addInterceptor(mLoggingInterceptor);
mClient = clientBuilder.build();`
I am pretty clueless here since it doesn't happen a lot and i cant reproduce it on my device.
I鈥檓 similarly clueless. Another file leak elsewhere in your program could be causing this.
It is highly unlikely since all those threads are associated with Okhttp. they are associated with a very simple task that updates our server with certain info once in every few seconds.
This happens mostly in a country with many network problems and i've got a feeling that due to a timeout or some other network issue the call fails and the Okio stream is not being closed properly.
What is really causing trouble is that after getting many exception like the one described above, we are getting the following one:
Fatal Exception: java.lang.OutOfMemoryError: Could not allocate JNI Env
at java.lang.Thread.nativeCreate(Thread.java)
at java.lang.Thread.start(Thread.java:1063)
at okhttp3.internal.framed.FramedConnection.(FramedConnection.java:173)
at okhttp3.internal.framed.FramedConnection.(FramedConnection.java:55)
at okhttp3.internal.framed.FramedConnection$Builder.build(FramedConnection.java:577)
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:161)
at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111)
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
at okhttp3.RealCall.getResponse(RealCall.java:240)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
If you can provide a test case to reproduce the leak, that鈥檇 be a great help.
In case anyone's still looking for a possible solution, here's one,
I made the mistake of instantiating OkHttpClient on every API call while injecting dependencies manually in my app, which resulted in too many open sockets and thus this error.
Tip: Make sure you are having a single instance of OkHttpClient and Retrofit in your app and reusing that.
This issue happened to me if you start 200 http request in the same time on a phone.
This happened to me when I started more than 300 HTTP requests from android mobile.
Most helpful comment
In case anyone's still looking for a possible solution, here's one,
I made the mistake of instantiating
OkHttpClienton every API call while injecting dependencies manually in my app, which resulted in too many open sockets and thus this error.Tip: Make sure you are having a single instance of
OkHttpClientandRetrofitin your app and reusing that.