Android: Out of Memory error StringBuilder

11,424

Solution 1

If you do not have enough memory to store your string you can: free some memory, reduce memory consumtion and do not store string in memory.

In your case you need:

  • memory to store response (around 1.5+mb)
  • memory for string builder (around 1.5+mb)
  • memory for resulting string (around 1.5+mb continious memory, very bad)
  • BufferedReader/InputStreamReader...etc. (some kilos)

Options:

  1. Convert response to a String without string builder. It will save 1+mb.
  2. Read response as a stream and convert it to a String without string builder. Request/Response entity streaming. It will save around 3mb
  3. Do not convert response to a string. Read it as stream and save to a file or db, or give a stream to streaming JSON parser.
  4. Free as much memory as you can before sending your post request and start praying that everything will be alright.

Solution 2

Just add this to the <application /> tag in your manifest:

android:largeHeap="true"
Share:
11,424

Related videos on Youtube

Nitish
Author by

Nitish

Updated on September 16, 2022

Comments

  • Nitish
    Nitish over 1 year

    In my app, I fetching data from the server in the form of JSON. The data is around 1.5 MB. The app works but sometimes it crashes while fetching data from server giving OutOfMemoryError.

    This is my method:

    private String sendPostRequest(String url, List<NameValuePair> params)
            throws Exception {
        String ret = null;
    
        BufferedReader bufferedReader = null;
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost request = new HttpPost(url);
    
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params);
            request.setEntity(entity);
    
            HttpResponse response = httpClient.execute(request);
    
            bufferedReader = new BufferedReader(new InputStreamReader(response
                    .getEntity().getContent()));
            StringBuilder stringBuilder = new StringBuilder("");
            StringBuilder stringBuilder2;
            String line = "";
            //String LineSeparator = System.getProperty("line.separator");
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
            bufferedReader.close();
    
            ret = stringBuilder.toString();
            stringBuilder = null;
    
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            // TODO: report an error
        } catch (IOException e) {
            e.printStackTrace();
            // TODO: report an error
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    // TODO Auto-generated catch block
                }
            }
        }
        return ret;
    }
    

    I tried setting the StringBuilder to null after use but didn't helped. I am posting the logcat traces below:

    10-23 03:39:25.271: E/dalvikvm-heap(1011): Out of memory on a 4116282-byte allocation.
    10-23 03:39:25.271: I/dalvikvm(1011): "AsyncTask #1" prio=5 tid=11 RUNNABLE
    10-23 03:39:25.271: I/dalvikvm(1011):   | group="main" sCount=0 dsCount=0 obj=0x417c5e88 self=0x2a1d1db8
    10-23 03:39:25.271: I/dalvikvm(1011):   | sysTid=1025 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=706552328
    10-23 03:39:25.271: I/dalvikvm(1011):   | state=R schedstat=( 3053328788 23773807212 6541 ) utm=241 stm=64 core=0
    10-23 03:39:25.271: I/dalvikvm(1011):   at java.lang.String.<init>(String.java:~422)
    10-23 03:39:25.271: I/dalvikvm(1011):   at java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:642)
    10-23 03:39:25.282: I/dalvikvm(1011):   at java.lang.StringBuilder.toString(StringBuilder.java:663)
    10-23 03:39:25.282: I/dalvikvm(1011):   at com.dzo.redacted.driverapp.datalayer.ServerConnect.sendPostRequest(ServerConnect.java:128)
    10-23 03:39:25.282: I/dalvikvm(1011):   at com.dzo.redacted.driverapp.datalayer.ServerConnect.Sync(ServerConnect.java:61)
    10-23 03:39:25.282: I/dalvikvm(1011):   at com.dzo.redacted.driverapp.datalayer.DBSync.Login(DBSync.java:59)
    10-23 03:39:25.282: I/dalvikvm(1011):   at com.dzo.redacted.driverapp.asynctask.SyncDBTask.doInBackground(SyncDBTask.java:52)
    10-23 03:39:25.282: I/dalvikvm(1011):   at com.dzo.redacted.driverapp.asynctask.SyncDBTask.doInBackground(SyncDBTask.java:1)
    10-23 03:39:25.282: I/dalvikvm(1011):   at android.os.AsyncTask$2.call(AsyncTask.java:287)
    10-23 03:39:25.282: I/dalvikvm(1011):   at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    10-23 03:39:25.282: I/dalvikvm(1011):   at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    10-23 03:39:25.282: I/dalvikvm(1011):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    10-23 03:39:25.282: I/dalvikvm(1011):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    10-23 03:39:25.282: I/dalvikvm(1011):   at java.lang.Thread.run(Thread.java:841)
    10-23 03:39:25.282: W/dalvikvm(1011): threadid=11: thread exiting with uncaught exception (group=0x41465700)
    10-23 03:39:25.292: I/Choreographer(1011): Skipped 30 frames!  The application may be doing too much work on its main thread.
    10-23 03:39:25.491: E/AndroidRuntime(1011): FATAL EXCEPTION: AsyncTask #1
    10-23 03:39:25.491: E/AndroidRuntime(1011): java.lang.RuntimeException: An error occured while executing doInBackground()
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at android.os.AsyncTask$3.done(AsyncTask.java:299) 
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.FutureTask.run(FutureTask.java:239)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.lang.Thread.run(Thread.java:841)
    10-23 03:39:25.491: E/AndroidRuntime(1011): Caused by: java.lang.OutOfMemoryError
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.lang.String.<init>(String.java:422)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:642)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.lang.StringBuilder.toString(StringBuilder.java:663)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at com.dzo.redacted.driverapp.datalayer.ServerConnect.sendPostRequest(ServerConnect.java:128)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at com.dzo.redacted.driverapp.datalayer.ServerConnect.Sync(ServerConnect.java:61)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at com.dzo.redacted.driverapp.datalayer.DBSync.Login(DBSync.java:59)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at com.dzo.redacted.driverapp.asynctask.SyncDBTask.doInBackground(SyncDBTask.java:52)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at com.dzo.redacted.driverapp.asynctask.SyncDBTask.doInBackground(SyncDBTask.java:1)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    10-23 03:39:25.491: E/AndroidRuntime(1011):     ... 4 more
    10-23 03:39:28.091: E/WindowManager(1011): Activity com.dzo.redacted.driverapp.LoginActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4178fcb0 V.E..... R.....ID 0,0-479,96} that was originally added here
    10-23 03:39:28.091: E/WindowManager(1011): android.view.WindowLeaked: Activity com.dzo.redacted.driverapp.LoginActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4178fcb0 V.E..... R.....ID 0,0-479,96} that was originally added here
    10-23 03:39:28.091: E/WindowManager(1011):  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:345)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:239)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.app.Dialog.show(Dialog.java:281)
    10-23 03:39:28.091: E/WindowManager(1011):  at com.dzo.redacted.driverapp.asynctask.SyncDBTask.onPreExecute(SyncDBTask.java:43)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.AsyncTask.execute(AsyncTask.java:534)
    10-23 03:39:28.091: E/WindowManager(1011):  at com.dzo.redacted.driverapp.asynctask.LoginAsyncTask.onPostExecute(LoginAsyncTask.java:87)
    10-23 03:39:28.091: E/WindowManager(1011):  at com.dzo.redacted.driverapp.asynctask.LoginAsyncTask.onPostExecute(LoginAsyncTask.java:1)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.AsyncTask.finish(AsyncTask.java:631)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.AsyncTask.access$600(AsyncTask.java:177)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.Handler.dispatchMessage(Handler.java:99)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.os.Looper.loop(Looper.java:137)
    10-23 03:39:28.091: E/WindowManager(1011):  at android.app.ActivityThread.main(ActivityThread.java:5103)
    10-23 03:39:28.091: E/WindowManager(1011):  at java.lang.reflect.Method.invokeNative(Native Method)
    10-23 03:39:28.091: E/WindowManager(1011):  at java.lang.reflect.Method.invoke(Method.java:525)
    10-23 03:39:28.091: E/WindowManager(1011):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    10-23 03:39:28.091: E/WindowManager(1011):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    10-23 03:39:28.091: E/WindowManager(1011):  at dalvik.system.NativeStart.main(Native Method)
    10-23 03:44:25.761: I/Process(1011): Sending signal. PID: 1011 SIG: 9
    

    Update 1

    I tried with this approach again it gave error with toString()in my case also, it is giving error with toString(). The same happened while I tried with Amit's answer. Is there anything with toString().

    Update 2

    Removed creation of new String builder object from while loop and now I am not using line separator. But, it didn't made much difference. The app runs for first time. But, if I try to run continuously for 2-3 times, the same problem occurs again.

    • Nitish
      Nitish over 10 years
      Thanks but, the app will run on phones and tablets, so I cannot increase heap size of a phone
  • Nitish
    Nitish over 10 years
    didn't worked...Still getting OutOfMemoryError for the same reason
  • Nitish
    Nitish over 10 years
    Can you shed some light on finding wrong in the above approach.
  • Nitish
    Nitish over 10 years
    Thanx for pointing out the bug. I had opted for 3rd solution. It works fine.
  • Rat-a-tat-a-tat Ratatouille
    Rat-a-tat-a-tat Ratatouille over 10 years
    Sir, does that mean if i pass an inputstream to gson itself directly, then i would not face the OOM exception that takes places when using a string builder? Please assist. Thanks
  • Michael
    Michael over 9 years
    I do not understand how a device with 512MB RAM and plenty free can have trouble allocating a paltry 6 or 8MB for a string.
  • Michael
    Michael over 9 years
    @Nitish The StringBuilder is still there but is being hidden in a string + operator.
  • Naveen Kumar M
    Naveen Kumar M over 8 years
    Hi Leonidos / Nitish, Can you please give me reference link for 3rd option?
  • Omid Heshmatinia
    Omid Heshmatinia almost 4 years
    It is not a fix, it just hides the problem.