square/moshi

Out of memory error

MihirModiIndianic opened this issue · 2 comments

Please find below sample code

  val inputStream: InputStream = FileInputStream(decompressedFilePath)
        val moshi = Moshi.Builder().build()
        val type: Type = Types.newParameterizedType(
            List::class.java,
            ItrDataModel::class.java
        )
        val adapter: JsonAdapter<List<ItrDataModel>> = moshi.adapter(type)
        var list: kotlin.collections.List<ItrDataModel> = adapter.fromJson(inputStream.source().buffer())!!

Detailed error below

FATAL EXCEPTION: main
Process: com.app.acompletions, PID: 31667
java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 404944 free bytes and 395KB until OOM, target footprint 201326592, growth limit 201326592; giving up on allocation because <1% of heap free after GC.
at com.commissioning.data.model.register.assets.ButtonItemJsonAdapter.fromJson(ButtonItemJsonAdapter.kt:77)
at com.commissioning.data.model.register.assets.ButtonItemJsonAdapter.fromJson(ButtonItemJsonAdapter.kt:23)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.squareup.moshi.CollectionJsonAdapter.fromJson(CollectionJsonAdapter.java:81)
at com.squareup.moshi.CollectionJsonAdapter$2.fromJson(CollectionJsonAdapter.java:55)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.commissioning.data.model.register.assets.QuestionsItemJsonAdapter.fromJson(QuestionsItemJsonAdapter.kt:60)
at com.commissioning.data.model.register.assets.QuestionsItemJsonAdapter.fromJson(QuestionsItemJsonAdapter.kt:25)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.squareup.moshi.CollectionJsonAdapter.fromJson(CollectionJsonAdapter.java:81)
at com.squareup.moshi.CollectionJsonAdapter$2.fromJson(CollectionJsonAdapter.java:55)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.commissioning.data.model.register.assets.BodyItemJsonAdapter.fromJson(BodyItemJsonAdapter.kt:51)
at com.commissioning.data.model.register.assets.BodyItemJsonAdapter.fromJson(BodyItemJsonAdapter.kt:25)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.squareup.moshi.CollectionJsonAdapter.fromJson(CollectionJsonAdapter.java:81)
at com.squareup.moshi.CollectionJsonAdapter$2.fromJson(CollectionJsonAdapter.java:55)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.commissioning.data.model.register.assets.ItrDataModelJsonAdapter.fromJson(ItrDataModelJsonAdapter.kt:93)
at com.commissioning.data.model.register.assets.ItrDataModelJsonAdapter.fromJson(ItrDataModelJsonAdapter.kt:26)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.squareup.moshi.CollectionJsonAdapter.fromJson(CollectionJsonAdapter.java:81)
at com.squareup.moshi.CollectionJsonAdapter$2.fromJson(CollectionJsonAdapter.java:55)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at com.squareup.moshi.JsonAdapter.fromJson(JsonAdapter.java:58)
at com.commissioning.ui.register.assets.viewmodel.RegisterAssetsViewModel.readJsonFile$acompletions_develop(RegisterAssetsViewModel.kt:258)
at com.commissioning.ui.register.assets.RegisterAssetsListFragment$setObserver$$inlined$observeNotNull$5.onChanged(LifeCycleExt.kt:147)
at com.commissioning.utils.listener.SingleLiveEvent.observe$lambda$0(SingleLiveEvent.kt:24)
at com.commissioning.utils.listener.SingleLiveEvent.$r8$lambda$Rear63-AvPH9BBEWqXK8qGmalrA(Unknown Source:0)
at com.commissioning.utils.listener.SingleLiveEvent$$ExternalSyntheticLambda0.onChanged(Unknown Source:4)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at com.commissioning.utils.listener.SingleLiveEvent.setValue(SingleLiveEvent.kt:32)
at com.commissioning.ui.register.assets.viewmodel.RegisterAssetsViewModel$downLoadGZipFromURL$1.invokeSuspend(RegisterAssetsViewModel.kt:205)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
17:42:50.600 E at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@222f8fe, Dispatchers.Main.immediate]

When the out-of-memory error indicates that it cannot allocate a tiny amount of memory (in this case, 24 bytes) the problem is not indicated in the stack trace. Moshi code just happened to be running and be unlucky last person who tried to allocate.

In the current state of the heap as indicated by the exception message, literally any code that runs next will crash with an OOM. This is because a memory leak or over-provisioning of memory by some system has used up all available memory. You should use techniques like dumping the heap occasionally and looking for leaks, tools like LeakCanary, heap profiling in IDEs, etc. to try and see where all the space is going.

Moshi was just trying to do what you asked–deserialize some JSON–but there was no memory for it to do so. We have no control over this. The enclosing environment and its unavailable memory.

Thanks for your response. I fixed it by streaming it

JsonReader.of(inputStream.source().buffer()).use { reader ->
                reader.beginArray()
                try {
                    while (reader.hasNext()) {
                        adapter.fromJson(reader)?.let {
                            "readJsonFile ItrDataModel Id = ${it.assetItrNumber}".timber()
                            database.addITRFormDataModelLocal(ITRFormDataModelLocal(it.assetItrNumber!!, it.toJson()))
                            count++
                        }
                    }
                } catch (e: Exception) {
                    "readJsonFile Parse error".timber()
                    e.printStackTrace()
                }
            }