Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Out of memory exception in gson.fromJson()

I use the following code for converting Json string(strWebserviceResult) to my Object:

EntMyClass entMyClass = gson.fromJson(strWebserviceResult,EntMyClass.class);

When strWebserviceResult is large (about 2.5 MB) I get the Out of memory exception on this line on Android phone devices not in Tablet that has larger memory.

How can I solve that.

Does anybody have any suggestion?

05-26 15:52:49.607: E/dalvikvm-heap(2078): Out of memory on a 9200-byte allocation.
05-26 15:52:49.618: E/dalvikvm(2078): Out of memory: Heap Size=31879KB, Allocated=27693KB, Bitmap Size=936KB, Limit=32768KB
05-26 15:52:49.618: E/dalvikvm(2078): Extra info: Footprint=31879KB, Allowed Footprint=31879KB, Trimmed=7400KB
05-26 15:52:49.618: E/AndroidRuntime(2078): FATAL EXCEPTION: Thread-19
05-26 15:52:49.618: E/AndroidRuntime(2078): java.lang.OutOfMemoryError: (Heap Size=31879KB, Allocated=27693KB, Bitmap Size=936KB)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at java.util.ArrayList.add(ArrayList.java:123)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter.deserialize(DefaultTypeAdapters.java:664)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter.deserialize(DefaultTypeAdapters.java:624)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:51)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:92)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler(JsonObjectDeserializationVisitor.java:117)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.ReflectingFieldNavigator.visitFieldsReflectively(ReflectingFieldNavigator.java:63)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:120)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationContextDefault.fromJsonObject(JsonDeserializationContextDefault.java:76)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:54)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter.deserialize(DefaultTypeAdapters.java:663)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter.deserialize(DefaultTypeAdapters.java:624)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:51)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:92)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:80)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:101)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:67)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:52)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.Gson.fromJson(Gson.java:551)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.Gson.fromJson(Gson.java:498)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.Gson.fromJson(Gson.java:467)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.Gson.fromJson(Gson.java:417)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at com.google.gson.Gson.fromJson(Gson.java:389)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at org.mabna.order.businessLayer.BoWebService.getDataForUpdate(BoWebService.java:188)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at org.mabna.order.ui.ActToolDataExchange.threadGetDataForFullUpdate(ActToolDataExchange.java:371)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at org.mabna.order.ui.ActToolDataExchange.access$9(ActToolDataExchange.java:362)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at org.mabna.order.ui.ActToolDataExchange$33.run(ActToolDataExchange.java:603)
05-26 15:52:49.618: E/AndroidRuntime(2078):     at org.mabna.order.utils.Utilities$5.run(Utilities.java:778)
like image 793
Bobs Avatar asked May 26 '12 11:05

Bobs


3 Answers

As with the other post, I would ask whether there is any way to avoid large memory usage with your app. If you can do that, it will be the most optimal solution. If your app really needs that much memory, you can try setting android:largeHeap="true" for your application in the manifest. Here is the reference:

http://developer.android.com/reference/android/R.styleable.html#AndroidManifestApplication_largeHeap

See this video for more information:

http://www.youtube.com/watch?v=_CruQY55HOk

like image 115
jsmith Avatar answered Oct 17 '22 20:10

jsmith


Try using the fromJson method that takes a JsonReader as input instead. This should allow you to not need the whole input string to be in memory at one time. Here's some sample code:

        final HttpURLConnection c = (HttpURLConnection) url.openConnection();
        final InputStreamReader isr = new InputStreamReader(c.getInputStream());
        final JsonReader reader = new JsonReader(isr);
        final EntMyClass entMyClass = GSON.fromJson(reader, EntMyClass.class);
        reader.close();
        c.disconnect();
like image 6
Joe Avatar answered Oct 17 '22 21:10

Joe


First of all. Do you really need to load 2.5MB data into memory?
At first there is created a big string, then it's parsed (another objects in memory), and then there is created a huge instance of EntMyClass. This approach is really inefficient.

I guess you have List in this object. Having only information you've provided I'd suggest to stream data into database. Then you can create adapter to show data in ListView.

There is a lot of ways how to do it. I'm using Jackson library because is the fastest, GSON should have similar functions.

Assuming you have a list in this object below is example how to store json array in database:

    //create parser
    final JsonParser jsonParser = objectMapper.getJsonFactory().createJsonParser(inputStream);

    JsonToken jsonToken = jsonParser.nextToken();
    while ((jsonToken = jsonParser.nextToken()) != null && jsonToken != JsonToken.END_ARRAY) {
        //map json object to ItemClass
        final ItemClass item = jsonParser.readValueAs(ItemClass.class);
        //store in database
        itemDAO.insert(item);
    }

And surround it with database transaction, not only data will be rollback in case of error but it's also more efficient.

like image 3
pawelzieba Avatar answered Oct 17 '22 20:10

pawelzieba