Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crashing on Android with only a Canvas #1512

Closed
gustavomts opened this issue Apr 20, 2023 · 19 comments · Fixed by #2865
Closed

Crashing on Android with only a Canvas #1512

gustavomts opened this issue Apr 20, 2023 · 19 comments · Fixed by #2865
Labels
bug Something isn't working released

Comments

@gustavomts
Copy link

gustavomts commented Apr 20, 2023

Description

For some reason, the app is crashing on Android after opening a modal with Canvas multiple times. Each time the modal is opened the memory usage goes up but it doesn't go back down when it's closed.

This problem was also happening on iOS but it seems like it was fixed in 0.1.184 beta.

This problem didn't seem to exist in v0.1.176 for Android.

Version

0.1.182 and 0.1.185

Steps to reproduce

Basically, you just need to keep opening and closing the modal until the app crashes.

Snack, code example, screenshot, or link to a repository

https://github.com/ivensgustavo/rnskia-android-crash

@gustavomts gustavomts added the bug Something isn't working label Apr 20, 2023
@chrfalch
Copy link
Contributor

Hi @gustavomts! Thanks for the report and the example. With the latest version I'm not able to make it crash. The memory seems to be released correctly released when the Modal is dismissed. I'm running the profiler on an Android device. The fix we had in 0.1.184 was primarily targeting a regression we had on iOS that was not happening on Android. Could you try to profile the behaviour you're seeing and / or debug to see where or why it is crashing?

@gustavomts
Copy link
Author

Hi @chrfalch, sure. I'll try to get back to you before the end of the week.

@gustavomts
Copy link
Author

@chrfalch I have some logs here

2023-04-24 11:08:13.908 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 55 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:13.910 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:16.105 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:17.308 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:20.556 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:22.428 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:24.534 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:26.486 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:27.918 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 54 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:27.921 28184-8145  OpenGLRenderer          com.rnskiacrash                      I  Davey! duration=992ms; Flags=0, IntendedVsync=25991502724076, Vsync=25991569390740, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=25991581687105, AnimationStart=25991581689345, PerformTraversalsStart=25992490084071, DrawStart=25992490230789, SyncQueued=25992490700321, SyncStart=25992491538602, IssueDrawCommandsStart=25992492231779, SwapBuffers=25992494698602, FrameCompleted=25992496200165, DequeueBufferDuration=379531, QueueBufferDuration=728698, GpuCompleted=25958811601184, 
2023-04-24 11:08:28.401 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:28.566 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:29.713 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:30.647 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:33.016 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:33.603 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:33.829 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:34.765 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:38.816 28184-28184 unknown:ReactModalHost  com.rnskiacrash                      E  Creating new dialog from context: com.rnskiacrash.MainActivity@e589d42@240688450
2023-04-24 11:08:39.527 28184-8145  OpenGLRenderer          com.rnskiacrash                      I  Davey! duration=715ms; Flags=1, IntendedVsync=26003386098672, Vsync=26003386098672, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=26003386509687, AnimationStart=26003386511042, PerformTraversalsStart=26003881847080, DrawStart=26004041132669, SyncQueued=26004092232310, SyncStart=26004092662726, IssueDrawCommandsStart=26004092768872, SwapBuffers=26004101621738, FrameCompleted=26004102203821, DequeueBufferDuration=103125, QueueBufferDuration=306198, GpuCompleted=0, 
2023-04-24 11:08:39.528 28184-28184 unknown:ReactModalHost  com.rnskiacrash                      E  Updating existing dialog with context: com.rnskiacrash.MainActivity@e589d42@240688450
2023-04-24 11:08:39.528 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 42 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:40.480 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:42.603 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 35 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:43.943 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 78 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:44.015 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:44.015 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:45.207 28184-28184 unknown:ReactModalHost  com.rnskiacrash                      E  Creating new dialog from context: com.rnskiacrash.MainActivity@e589d42@240688450
2023-04-24 11:08:45.692 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 36 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:45.803 28184-28184 unknown:ReactModalHost  com.rnskiacrash                      E  Updating existing dialog with context: com.rnskiacrash.MainActivity@e589d42@240688450
2023-04-24 11:08:47.226 28184-8145  OpenGLRenderer          com.rnskiacrash                      D  endAllActiveAnimators on 0xb4000076b13b7300 (LayerDrawable) with handle 0xb4000076d55a6960
2023-04-24 11:08:47.860 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 45 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:47.869 28184-8145  OpenGLRenderer          com.rnskiacrash                      I  Davey! duration=784ms; Flags=0, IntendedVsync=26011652765731, Vsync=26011652765731, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=26011653152334, AnimationStart=26011653153271, PerformTraversalsStart=26012433451630, DrawStart=26012433543818, SyncQueued=26012433688037, SyncStart=26012434428818, IssueDrawCommandsStart=26012434592620, SwapBuffers=26012436153193, FrameCompleted=26012438023922, DequeueBufferDuration=343594, QueueBufferDuration=1144427, GpuCompleted=25959886312958, 
2023-04-24 11:08:48.561 28184-28184 Choreographer           com.rnskiacrash                      I  Skipped 36 frames!  The application may be doing too much work on its main thread.
2023-04-24 11:08:48.611 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
2023-04-24 11:08:48.770 28184-8193  ReactNativeJNI          com.rnskiacrash                      I  Memory warning (pressure level: TRIM_MEMORY_RUNNING_LOW) received by JS VM, ignoring because it's non-severe
2023-04-24 11:08:49.504  1726-2405  InputDispatcher         system_server                        E  channel 'b285455 com.rnskiacrash/com.rnskiacrash.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

In this video, you can see the app increasing the memory usage until it crashes. It takes a while so I had to cut it short, but you can still notice how the memory usage grows.
https://user-images.githubusercontent.com/39544919/234285127-d3d6657b-ed07-4fef-83d9-3e09b2e57d0c.mp4

@hitman249
Copy link

hitman249 commented Jun 6, 2023

  public afterMount(): void {
    setTimeout(this.toggle, 1000);
  }

  @bind
  public toggle(): void {
    this.setState({visible: !Boolean(this.state.visible)}, () => {
      setTimeout(this.toggle, 1);
    });
  }

  public render(): any {
    if (this.state.visible) {
      return (
        <Canvas key={'canvas'} style={{ width: '100%', height: 300, display: 'flex'}}>
          <Circle cx={128} cy={128} r={128} color="lightblue"/>
        </Canvas>
      );
    }
  }

I confirm, this code crashes the application in 30 seconds.
Android 9
Version 0.1.193

checked version 0.1.176, the application crashes there too

Update
There is no memory leak when using SkiaView

<SkiaView onDraw={this.onDraw}/>

@chrfalch
Copy link
Contributor

chrfalch commented Jun 7, 2023

The example was not possible to run out of the box, but I created this example component:

export const Breathe = () => {
  const [visible, setVisible] = React.useState(true);
  const update = () => {
    setTimeout(() => {
      setVisible((v) => !v);
      update();
    }, 1000);
  };
  useEffect(() => {
    update();
  }, []);

  return visible ? (
    <Canvas
      key={"canvas"}
      style={{ width: "100%", height: 300, display: "flex" }}
    >
      <Circle cx={128} cy={128} r={128} color="lightblue" />
    </Canvas>
  ) : null;
};

When run in Android it refreshes every second, and the memory stays pretty stable over time (we see a small increase in memory but no crash - how long do you need to run this to see the crash?

@hitman249
Copy link

With your interval of 1000 milliseconds, I need to wait 1000 times longer, because in my case the interval is 1 millisecond.

1000 * 30 = 30000 seconds
30000 / 60 = 500 minutes
500 / 60 = 8,3 hours

Your example will crash in only 8 hours..

In a real application from production, the frequency of re-creating the canvas reaches ~10+ times per second

@chrfalch
Copy link
Contributor

chrfalch commented Jun 7, 2023

Makes sense, I just took the numbers from your example where you used 1000 ms as the timeout :) :)

@chrfalch
Copy link
Contributor

chrfalch commented Jun 7, 2023

We would definetly look for another way to solve this than by recreating the Canvas so often. Could you describe your use case a bit more?

@hitman249
Copy link

hitman249 commented Jun 7, 2023

<VerticalList>
  <HorizontalList>[canvas1][canvas2]</HorizontalList>
  <HorizontalList>[canvas1][canvas2]</HorizontalList>
  <HorizontalList>[canvas1][canvas2]</HorizontalList>
  <HorizontalList>[canvas1][canvas2]</HorizontalList>
  ...
</VerticalList>

When scrolling HorizontalList to the right, the canvas jumps into view.
When changing the screen, all these canvases are deleted, others are created, which leads to the crash of the application within ~ 10 minutes of continuous use.

Update
Specifically for me, the task is not relevant.

I rewrote my project to the imperative style and SkiaView, as a result of which the memory leaks disappeared, and the code began to work faster than through Canvas.

@cjhines
Copy link
Contributor

cjhines commented Jul 13, 2023

@hitman249 Could you please share your leak-free implementation? I'm curious what the imperative style looks like

@hitman249
Copy link

@cjhines

@hitman249 Could you please share your leak-free implementation? I'm curious what the imperative style looks like

An example is in the documentation
Custom Drawing

@wcandillon
Copy link
Contributor

@hitman249 I would be curious to see the code that runs faster in SkiaView than Canvas. I would also be curious to look at the suspected memory leak

@cjhines
Copy link
Contributor

cjhines commented Aug 2, 2023

In my issue discussing the crash present in the workaround, I observed that even an empty canvas is gradually accumulating memory.

Screenshot 2023-08-02 at 11 38 02
Screen.Recording.2023-08-02.at.11.40.39.mov

@wcandillon
Copy link
Contributor

@cjhines do you have a small reproducible example for this?

@cjhines
Copy link
Contributor

cjhines commented Aug 3, 2023

@wcandillon Sure! Here's a repo: https://github.com/cjhines/skia-memory-example

By repeatedly opening and closing the second screen with the buttons on the top, you will see memory consumption growing rapidly.

In our real app this is even worse due to SVG variety.

memory.mov

@chrfalch
Copy link
Contributor

chrfalch commented Aug 3, 2023

Thanks, @cjhines - I'm looking into this - the example is a bit big and we'd like to be able to reduce any number of potential causes for this to fail, would it be possible to reduce it to a single source file without any other dependencies than RN Skia (and Reanimated + navigation (stack/tabs)) if possible? Would help us a lot.

@cjhines
Copy link
Contributor

cjhines commented Aug 3, 2023

@chrfalch Hugely appreciated! I've pushed a commit to simplify the project to be contained in App.tsx and removed many unrelated dependencies.

@chrfalch
Copy link
Contributor

chrfalch commented Aug 3, 2023

Thanks, appreciate it!

Copy link
Contributor

🎉 This issue has been resolved in version 1.10.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working released
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants