question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Opening and closing the session details screen repeatedly causes the app to crash with an OOM error.

See original GitHub issue

Describe the bug I don’t know how to deal with this yet without further investigation, but the titular phenomenon occurs.

To Reproduce

  1. open the Session List screen
  2. display the session details screen one by one and return to it
  3. continue to do 2. although the operation becomes slower
  4. finally, no more operations are accepted and OOM error occurs and the app crashes

Expected behavior

  1. the screen does not get choppy when opening the session details screen
  2. no matter how many times I open the session detail screen, the app does not crash with an OOM error

Screenshots

FATAL EXCEPTION: OkHttp Dispatcher
                                                                                                    Process: io.github.droidkaigi.confsched2022.dev, PID: 20572
                                                                                                    java.lang.OutOfMemoryError: Failed to allocate a 370792 byte allocation with 76488 free bytes and 74KB until OOM, target footprint 268435456, growth limit 268435456
                                                                                                    	at java.lang.StringFactory.newStringFromUtf8Bytes(Native Method)
                                                                                                    	at java.lang.StringFactory.newStringFromBytes(StringFactory.java:80)
                                                                                                    	at java.lang.StringFactory.newStringFromBytes(StringFactory.java:101)
                                                                                                    	at okio.Buffer.readString(Buffer.kt:313)
                                                                                                    	at okio.Buffer.readString(Buffer.kt:302)
                                                                                                    	at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:270)
                                                                                                    	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
                                                                                                    	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
                                                                                                    	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                                                                                                    	at java.lang.Thread.run(Thread.java:1012)
2022-09-16 23:33:01.011 20572-20733 Process                 io.....droidkaigi.confsched2022.dev  I  Sending signal. PID: 20572 SIG: 9
---------------------------- PROCESS ENDED (20572) for package io.github.droidkaigi.confsched2022.dev ----------------------------

スクリーンショット 2022-09-16 23 33 48

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

3reactions
eneimcommented, Sep 19, 2022

One interesting observation: Using lambda in the click callbacks may result in more and more allocations in the memory when you go back and forth.

For example: DrawerSheetContent.onClickDrawerItem using lambda will allocate new objects everytime you click a Session to open its detail, and go back. Below is the memory dump between 0 click and 10 clicks (open the Session and go back):

App just starts Open 10 Sessions and back
Screen Shot 2022-09-19 at 22 10 34 Screen Shot 2022-09-19 at 22 11 46

NOTE: it seems that Andriod Studio EE doesn’t show the correct value of Retained Size. Profiling the App in Android Studio Dolphin gives you the correct number.

By changing lambda to method reference, I can see no new objects are allocated by the clicks. The code change is below:

Index: app-android/src/main/java/io/github/droidkaigi/confsched2022/KaigiApp.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/app-android/src/main/java/io/github/droidkaigi/confsched2022/KaigiApp.kt b/app-android/src/main/java/io/github/droidkaigi/confsched2022/KaigiApp.kt
--- a/app-android/src/main/java/io/github/droidkaigi/confsched2022/KaigiApp.kt	(revision 078733be2788476f4f8d06ca9dfab1f2fb58cb68)
+++ b/app-android/src/main/java/io/github/droidkaigi/confsched2022/KaigiApp.kt	(date 1663593865466)
@@ -103,9 +103,7 @@
                 drawerSheetContent = {
                     DrawerSheetContent(
                         selectedDrawerItem = kaigiAppScaffoldState.selectedDrawerItem,
-                        onClickDrawerItem = { drawerItem ->
-                            kaigiAppScaffoldState.navigate(drawerItem)
-                        }
+                        onClickDrawerItem = kaigiAppScaffoldState::navigate,
                     )
                 }
             ) {

Memory dump of the same suspicious object after opening a Session 0 times and 10 times: (Notice how the total allocation counts are changed significantly, but the number of the highlighted object is the same).

App just starts Open a Session 10 times
Screen Shot 2022-09-19 at 22 02 26 Screen Shot 2022-09-19 at 22 03 59

I just try with one lambda in this case, I think if we double check all other places, we can optimize it further. Though it can just be a part of the whole OOM problem.

1reaction
eneimcommented, Sep 24, 2022

@Corvus400 @takahirom Not a big progress, but some investigation result:

  • With the current implementation (DrawerSheetContent.onClickDrawerItem is a lambda):
    • All items on the Drawer are re-composed every session-open-close (see video). I think the reason is that the viewModel is not a Stable object and then the lambda is not memorized correctly, causing it to be re-composed everytime the selectedDrawerItem changes.

https://user-images.githubusercontent.com/1776230/192099224-c35597fa-0f3d-4d68-9e41-78407b35381f.mov

  • Change DrawerSheetContent.onClickDrawerItem to method reference. This time, it is a stable type and only the top Navigation item is re-composed (see video).

https://user-images.githubusercontent.com/1776230/192099340-a83b5bee-b8b6-4d55-b1e2-ca599af90732.mov

So at least using method reference can improve the composing performance a little bit. I still see memory usage increasing, so the ultimate solution is not done yet.

I will send a small PR to change this callback to method reference. But keep in mind that it may not fix this issue completely 🙇 .


Additional observation:

I’m curious why opening the session detail will recompose the drawer’s item, and what I learned is that the Session NavGraph is at the same NavGraph as the Drawer’s NavGraph. So if I open the Session detail, it updates the Drawer’s navigation destination and therefore updates the selectedDrawerItem --> recompose the Drawer:

  • [Click drawer item] -> [Navigate] -> [Update selectedDrawerItem] -> [Recompose the Drawer].
  • [Click a Session item] -> [Navigate] -> [Update selectedDrawerItem] -> [Recompose the Drawer (even though the user doesn’t interact with the Drawer)].

Maybe we can use nested NavGraph for some Drawer items, such as the Sessions screen, so that navigating within a nested Graph doesn’t recompose the Drawer (see below):

https://user-images.githubusercontent.com/1776230/192099578-1f17d142-a76f-4c6c-9365-799d4b88706a.mov

An important note: simply changing to nested graph doesn’t work out of the box. The reason is:

  • Without using nested graph, the Drawer’s selected item is updated on any navigation destination change, including the Session details opening/closing.
  • Using nested graph, we need a different signal to update the Drawer’s selected item. And it may requires a bigger refactoring.

This observation and update proposal may not be impactful enough to refactor. So this is just a discussion point. If I were to design the navigation structure from the beginning, I would consider using nested graph where it is reasonable 😃 .

Read more comments on GitHub >

github_iconTop Results From Across the Web

What are Out Of Memory (OOM) Crashes and How to Avoid ...
Here are some tips and best practices you can use to reduce your app's memory footprint and eliminate OOMs.
Read more >
The case of iOS OOM Crashes at Compass - Medium
An OOM crash occurs anytime an app is killed by the system because it over-used RAM, when the OS decided to reclaim the...
Read more >
Zoom keeps crashing when someone shares their screen
My Zoom keeps crashing whenever someone in the meeting shares their screen. It usually happens when the number of people in the meeting...
Read more >
My VS code keeps crashing when opening it - Stack Overflow
The solution was to start VS Code from the command prompt with the following command: code --disable-extensions --max-memory=12288mb.
Read more >
Apps crash randomly on newly installed ubuntu 22.04
I had the same problem, and it turned out that systemd-oomd (a userspace out-of-memory (OOM) killer) was killing my applications whenever I ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found