Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient.execute throwing OutOfMemoryError

I've an Android application that posting JSONObject as a entity by using ByteArrayEntity object. Here how it looks like:

post.setEntity(new ByteArrayEntity(entity.getBytes("UTF-8")));
result = client.execute(post, handler);

Entity is a String. Handler is ResponseHandler<String> and client is a HttpClient. That's working well on emulator and on some devices. But, sometimes I'm getting OutOfMemoryError while executing on x10i (also known as XPERIA).

Here is stack:

java.lang.OutOfMemoryError
at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:79)
at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:93)
at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:171)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:580)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:678)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:652)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at com.test.application.api.Request.post(Request.java:102)
at com.test.application.api.API.getResult(API.java:123)
at com.test.application.api.APITask.doInBackground(APITask.java:127)
at com.test.application.api.APITask.doInBackground(APITask.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)

As I said, I'm just posting a JSONObject as a String. It may be 200 character at most. What's wrong?

like image 782
Ogulcan Orhan Avatar asked Dec 17 '12 11:12

Ogulcan Orhan


3 Answers

Android devices have a per-process memory limit. The default default is 24MB, but some devices have a lower value, eg 16MB or perhaps lower. The X10i appears to have 384MB RAM, which is low for a modern Android device (1GB is now standard), and this may place additional constraints.

I would suggest:

  1. First check the per-process limit on your device. Use ActivityManager.getMemoryClass() to check.
  2. Look at your actual memory usage using DDMS.

You may find that, just before you are making this call, you are already at the upper limit of memory; the initialisation of the HTTPClient and the call might take you just over the limit. This will be more likely if the OOM occurs on the first call.

If this happens only sporadically, or after a number of calls, you might have a memory leak. DDMS will help you track that down using the get allocations feature.

like image 69
Andrew Alcock Avatar answered Oct 31 '22 18:10

Andrew Alcock


In case of java.lang.OutOfMemoryError it's likely that your application keeps references to objects which should be freed. Try to debug this application on this phone, not in emulator.

like image 29
tcb Avatar answered Oct 31 '22 18:10

tcb


On the surface, only 200 bytes which are allocated not very often will not run the process out of memory even on Android. Therefore one of these assumptions is wrong. Most likely one of the following is true:

1) More than 200 bytes is being allocated in the failure case (for example, is a new HttpClient being allocated for every call).

2) This code is getting called very often

3) There is already a memory problem (like with images) and this was just the last allocation that took the app past its limits.

How many times has this line of code been the culprit of this problem? If the answer is many then 1) or 2) look likely. Since we do not have all the apps code it is hard to diagnose, but look to the event/circumstance that triggers this code -- is it getting called from a touch or move -- and if so is this happening every millisecond as the user drags their finger across the screen because there is no sleep in the onTouch loop? This is the kind of thing that could vary from platform to platform.

If this line of code has only caused the problem once or twice it may be time to look for a general memory usage problem. Try to determine how close to the memory limit the application is. The allowance varies with Android version, so this may be another reason why you don't see it in the emulator. Try to test with the same Android version that is experiencing the problem.

like image 1
hack_on Avatar answered Oct 31 '22 18:10

hack_on