sceneview-android
sceneview-android copied to clipboard
Memory leak
I just realized in my application that the ArSceneView.renderer is leaking so I've tried in the sample-ar-model-viewer demo and it seems that the leak is coming from the library. I could reproduce it by simply adding the leak-canary library to the sample. I've tried to clear the ArSceneView in the onDestroyView() of the fragment by setting it to null, but it didn't help. Here is the leak-canary heap analysis result:
HEAP ANALYSIS RESULT
====================================
1 APPLICATION LEAKS
References underlined with "~~~" are likely causes.
Learn more at https://squ.re/leaks.
1029 bytes retained by leaking objects
Signature: 99bf7c9da341a49ffdcbea9aef692c7f6673b96e
┬───
│ GC Root: System class
│
├─ android.view.inputmethod.InputMethodManager class
│ Leaking: NO (InputMethodManager↓ is not leaking and a class is never
│ leaking)
│ ↓ static InputMethodManager.sInstance
├─ android.view.inputmethod.InputMethodManager instance
│ Leaking: NO (ArSceneView↓ is not leaking and InputMethodManager is a
│ singleton)
│ ↓ InputMethodManager.mCurRootView
├─ android.view.ViewRootImpl instance
│ Leaking: NO (ArSceneView↓ is not leaking)
│ mContext instance of com.android.internal.policy.DecorContext, wrapping
│ activity io.github.sceneview.sample.armodelviewer.Activity with mDestroyed
│ = false
│ ViewRootImpl#mView is not null
│ mWindowAttributes.mTitle = "io.github.sceneview.sample.armodelviewer/io.
│ github.sceneview.sample.armodelviewer.Activity"
│ mWindowAttributes.type = 1
│ ↓ ViewRootImpl.mSurfaceChangedCallbacks
├─ java.util.ArrayList instance
│ Leaking: NO (ArSceneView↓ is not leaking)
│ ↓ ArrayList[0]
├─ io.github.sceneview.ar.ArSceneView instance
│ Leaking: NO (View attached)
│ View is part of a window view hierarchy
│ View.mAttachInfo is not null (view attached)
│ View.mID = R.id.sceneView
│ View.mWindowAttachCount = 1
│ mContext instance of io.github.sceneview.sample.armodelviewer.Activity
│ with mDestroyed = false
│ ↓ ArSceneView.renderer
│ ~~~~~~~~
├─ com.google.ar.sceneform.rendering.ArRenderer instance
│ Leaking: UNKNOWN
│ Retaining 2.1 kB in 40 objects
│ ↓ Renderer.viewAttachmentManager
│ ~~~~~~~~~~~~~~~~~~~~~
├─ com.google.ar.sceneform.rendering.ViewAttachmentManager instance
│ Leaking: UNKNOWN
│ Retaining 1.3 kB in 21 objects
│ ↓ ViewAttachmentManager.frameLayout
│ ~~~~~~~~~~~
╰→ android.widget.FrameLayout instance
Leaking: YES (ObjectWatcher was watching this because android.widget.
FrameLayout received View#onDetachedFromWindow() callback)
Retaining 1.0 kB in 16 objects
key = 974cd537-0dbb-4f32-9f2e-0a60998aa9d8
watchDurationMillis = 5934
retainedDurationMillis = 887
View not part of a window view hierarchy
View.mAttachInfo is null (view detached)
View.mWindowAttachCount = 1
mContext instance of io.github.sceneview.sample.armodelviewer.Activity
with mDestroyed = false
====================================
0 LIBRARY LEAKS
A Library Leak is a leak caused by a known bug in 3rd party code that you do
not have control over.
See https://square.github/.
io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
====================================
0 UNREACHABLE OBJECTS
An unreachable object is still in memory but LeakCanary could not find a strong
reference path
from GC roots.
====================================
METADATA
Please include this in bug reports and Stack Overflow questions.
Build.VERSION.SDK_INT: 30
Build.MANUFACTURER: Google
LeakCanary version: 2.9.1
App process name: io.github.sceneview.sample.armodelviewer
Class count: 19745
Instance count: 175695
Primitive array count: 92345
Object array count: 22352
Thread count: 43
Heap total bytes: 77566459
Bitmap count: 2
Bitmap total bytes: 180002
Large bitmap count: 0
Large bitmap total bytes: 0
Stats: LruCache[maxSize=3000,hits=38513,misses=102077,hitRate=27%]
RandomAccess[bytes=4736305,reads=102077,travel=32772117401,range=25257049,size=8
7653658]
Analysis duration: 22954 ms
Heap dump file path: /storage/emulated/0/Download/leakcanary-io.github.
sceneview.sample.armodelviewer/2022-05-23_15-36-58_886.hprof
Heap dump timestamp: 1653309451124
Heap dump duration: Unknown
====================================
Any updates on this issue? cc: @tamashalcyon, @ThomasGorisse
Even I observed the same issue using LeakCanary heap dump. Any quick work around to avoid this leak?
I tried making some things null when the view is destroyed, but with no success. I just tried outside the library, I didn't made any change inside the lib.
Can you try doing the same test with every SceneView instantiations commented? Just display the default SceneView/ARSceneView doing nothing else.
Good idea! I've commented everything, only an ArSceneView is visible to the user. The same leak is happening to me :/
I also have the same memory leak
Inside the com.google.ar.sceneform.rendering.Renderer there is a destroy() method which is not called at all as far as I've seen. I've tried calling that in the onDestroy() of the SceneView and also making the _renderable null, but it's still leaking.
I also used this leak test app in others contexts and the result is always with leak but this doesn't mean much. A real test would be to use the Android Studio memory analysis tools and to get the result on a GC (Garbage collect) action after destroyed.
Inside the com.google.ar.sceneform.rendering.Renderer there is a destroy() method which is not called at all as far as I've seen. I've tried calling that in the onDestroy() of the SceneView and also making the _renderable null, but it's still leaking.
You are right, that part is commented because it was used by the old Sceneform system that didn't really destroyed the Filament resources but more or less passing them to null so they can be garbage collected (destroyed when memory is needed by any other process) Since not 100% parts of Sceneform have been moved to the new lifecycle aware system yet of SceneView, some old not cleaned parts may still exist.
If you can tell us exactly what objects are still retaining memory before and after Garbage collector call, we will maybe be able to threat them. But the main objective is to move them to the new memory management system so it can be destroyed when the SceneView is.
For me destroying a modelNode doesn't fully unload it, because of this very leak. After a bit of loading and "unloading" models my app crashes.
If anyone knows some workaround it woould help a lot.
Can you debug the sceneView.destroy() and see if any of the destroy() call within it generates an Exception?
I have to admit that I intentionally didn't try catch the managers/entities possible double destroy in here in order to be sure that every used resources are correctly destroyed when they need to be.
What can happen is that one of those lines is throwing an earlier exiting exception.
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. Thank you for your contributions.
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.