I am using leak canary to test if any memory leaks are present in my game. My output shows jmesurfaceview keeping reference of activity context. here is snapshot
Am I missing something or is there issue with jmesurface view. I tried both destruction policy (destroy and keep) but memory leak persist. I have 2 activities one is main and other gameplay when press back button gameplay activity is finished.I guess jmeview.destroy and stop should release any context held in view or am I missing something ?
EDIT : Also calling destroy on view is not consistent sometimes it throws error Attempt to invoke virtual method 'void com.jme3.app.LegacyApplication.destroy()' on a null object reference
Hello @Anuj_Topiwala, thanks for reporting and testing, I appreciate that much!
I think I was aware of this memory leak during developing the JmeSurfaceView, but it isn’t related to JmeSurfaceView, it is something on the JmeAndroidSystem which is a part of the System delegate, that needs to keep a static reference of the context, I guess we could fix this by setting this reference to null when destroying the holding activity:
And this is the line that calls this function, keeping a static reference of the jmesurfaceview:
EDIT:
Could you please open an issue, when I find the time appropriate, I will submit a patch to fix this.
The code is guarded by a null-safe test, you should never invoke this manually (especially from other threads), what did you do specifically to manifest this?
Sorry for late reply. The thing is I already added following three calls on my GameplayActivity destroy to temporarily check if there is issue in my own code.
However for some API there is no memory leaks for some that I tested(28,29) there is leak.
But main issue is that even for those android api version that show no memory leak in profiler or leakcanary, native memory allocated is not released and keep on adding on multiple runs i.e after activity is finish when you restart it on button click memory keeps on adding.
This behaviour I guess could be result of issue raised here : https://github.com/jMonkeyEngine/jmonkeyengine/issues/1990
I am not aware of internals of jme so cannot say if the above leak is actual cause for memory cascading on multiple runs.
You don’t need to do this, JmeSurfaceView recycles and manages other stuff, doing so, may disable gainFocus and loseFocus and other lifecycle listeners which is useful, you can achieve the missing effect by just adding JmeAndroidSystem.setView(null) within your activity onDestroy().
Thanks for testing, I guess you are right, we were working on a memory allocation API, but there are still some untested aspects, regrading that, what type of applications are you working on? Does it utilize direct memory or create explicit buffers? (other than the ones that jme creates?).
EDIT:
Btw, if you want to take the chance and submit a fix for the JmeSurfaceView issue by adding the missing line at the destroy(), go ahead!
Thanks for testing, I guess you are right, we were working on a memory allocation API, but there are still some untested aspects, regrading that, what type of applications are you working on? Does it utilize direct memory or create explicit buffers? (other than the ones that jme creates?).
No I am not using any explicit Buffers.
I dont know if just adding the line will fix issue of cascading memory so not taking chance
The native memory issue is another topic that we are still working on, the original issue of this thread (which I am talking about) was the static reference leakage.
Though I am still evaluating if API 29 leak is because of my own code-usage of coroutines despite cancelling it prior to closure.
EDIT : My Suspicion was right API 29 was issue of my own code. However for avoiding memory leak need to set both SystemDelegate static reference and view static reference to null.
The primitive allocator has no support for deallocation so sure it does not throw out of memory error but my memory keeps accumulating on multiple runs. I changed to android native allocator, and manually set system property to reflection allocator(which I guess is default created by bufferallocatorfactory?), but native memory accumulates on every run.
The reflection allocator might work on some earlier Android APIs, but the android release gradle task of the AGP will restrict you from producing a release variant; because this type of reflection is a black flag now, which is why it was deprecated in the first place.