Android jmesurfaceView Memory Leak?

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

3 Likes

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.

3 Likes

I opened an issue, I will try to submit a fix as soon as possible:

2 Likes

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?

1 Like

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.

JmeAndroidSystem.getView()?.handler?.removeCallbacksAndMessages(null)
JmeAndroidSystem.setView(null)
JmeSystem.setSystemDelegate(null)

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.

1 Like

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!

1 Like

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 :smile:

1 Like

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.

1 Like

After adding this line, Can you still see a context instance hanging around after activity destruction?

As I said before in some API it does in some it does not. here is screenshot
API 29: leak even after setting static view reference null.

here is API 25 It does NOT leak.

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.

1 Like

For this, the simple solution is to switch to PrimitiveAllocator.

String implementation = BufferAllocatorFactory.PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION;
System.setProperty(implementation, PrimitiveAllocator.class.getName());

Note that this should be added before the app starts. (adding this after the app start (e.g. inside simpleInitApp) will have no effect!)

1 Like

Thanks will try this and check.

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.

1 Like

Yes I saw that issue and deprecation note and am not planning to use it either but was just testing for memory.

1 Like