Android memory allocation

I want my latest Project (which is running fine on desktop) port to Android. But it hangs after the nifty gui (when selected to start the game) it displays some derbies of the Terrain and freeze.


EDIT
through the adb log i’ve seen its a problem that the app runs out of memory when building the terrain (see my post further down for the new log snippet)

Is in the Meta Inf or somewhere else a possible to adjust the max allowable allocate memory for the app?

I have aready updated to the jme3-android-3.5.0-alpha1.jar & jme3-core-3.5.0-alpha1.jar
and use jme3-bullet-native-android-3.2.3-stable.jar and jme3-bullet-3.3.0-stable.jar

Does the problem occur with all libraries at the same version level, say 3.3.2-stable?

EDITED
I changed the name of this troubleshot threat, after I seen the out of memory exception.


please ignore that post. I have seen the avd was out of memory before the null pointer exceptions was thrown. Because the computer is new there is no abd installed to get logs from my smartphone. I try with a bigger virtual device.

1 Like

so I finally got log from my smartphone. But even there is an out of memory. It has 8GB like my desktop computer. Is somewhere in Android studio a config to specify the amount memory the app is allowed to allocate:

2021-12-12 21:41:32.173 24222-24329/de.hc.jeep2d W/de.lessvoid.nifty.NiftyMethodInvoker: WARNUNG Exception in callMethod(public void de.hc.jme.gui.controller.GuiController.startGame(java.lang.String)) for [de.hc.jme.gui.controller.GuiController@8b70580]
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at de.lessvoid.nifty.NiftyMethodInvoker.callMethod(NiftyMethodInvoker.java:157)
at de.lessvoid.nifty.NiftyMethodInvoker.performInvoke(NiftyMethodInvoker.java:102)
at de.lessvoid.nifty.Nifty$DelayedMethodInvoke.perform(Nifty.java:1481)
at de.lessvoid.nifty.Nifty.invokeMethods(Nifty.java:1457)
at de.lessvoid.nifty.Nifty.handleDynamicElements(Nifty.java:439)
at de.lessvoid.nifty.Nifty.access$1600(Nifty.java:87)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processEvent(Nifty.java:1727)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processMouseEvent(Nifty.java:1665)
at com.jme3.niftygui.InputSystemJme.handleMouseEvent(InputSystemJme.java:123)
at com.jme3.niftygui.InputSystemJme.onMouseButtonEventQueued(InputSystemJme.java:231)
at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:295)
at de.lessvoid.nifty.Nifty.update(Nifty.java:368)
at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:112)
at com.jme3.input.InputManager.processQueue(InputManager.java:859)
at com.jme3.input.InputManager.update(InputManager.java:923)
at com.jme3.app.LegacyApplication.update(LegacyApplication.java:774)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:247)
at com.jme3.app.AndroidHarness.update(AndroidHarness.java:499)
at com.jme3.system.android.OGLESContext.onDrawFrame(OGLESContext.java:350)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1582)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1281)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 4202512 byte allocation with 3274632 free bytes and 3197KB until OOM, target footprint 402653184, growth limit 402653184
at com.jme3.terrain.geomipmap.TerrainQuad.getHeightMap(TerrainQuad.java:1850)
at com.jme3.terrain.geomipmap.TerrainQuad.getHeightMap(TerrainQuad.java:1868)
at com.jme3.bullet.util.CollisionShapeFactory.createMeshShape(CollisionShapeFactory.java:188)
at com.jme3.bullet.control.RigidBodyControl.createCollisionShape(RigidBodyControl.java:239)
at com.jme3.bullet.control.RigidBodyControl.setSpatial(RigidBodyControl.java:203)
at com.jme3.scene.Spatial.addControl(Spatial.java:777)
at de.hc.jme.scene.Jeep2Scene.init(Jeep2Scene.java:73)
at de.hc.jme.gui.controller.GuiController.startGame(GuiController.java:64)
at java.lang.reflect.Method.invoke(Native Method)
at de.lessvoid.nifty.NiftyMethodInvoker.callMethod(NiftyMethodInvoker.java:157)
at de.lessvoid.nifty.NiftyMethodInvoker.performInvoke(NiftyMethodInvoker.java:102)
at de.lessvoid.nifty.Nifty$DelayedMethodInvoke.perform(Nifty.java:1481)
at de.lessvoid.nifty.Nifty.invokeMethods(Nifty.java:1457)
at de.lessvoid.nifty.Nifty.handleDynamicElements(Nifty.java:439)
at de.lessvoid.nifty.Nifty.access$1600(Nifty.java:87)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processEvent(Nifty.java:1727)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processMouseEvent(Nifty.java:1665)
at com.jme3.niftygui.InputSystemJme.handleMouseEvent(InputSystemJme.java:123)
at com.jme3.niftygui.InputSystemJme.onMouseButtonEventQueued(InputSystemJme.java:231)
at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:295)
at de.lessvoid.nifty.Nifty.update(Nifty.java:368)
at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:112)
at com.jme3.input.InputManager.processQueue(InputManager.java:859)
at com.jme3.input.InputManager.update(InputManager.java:923)
at com.jme3.app.LegacyApplication.update(LegacyApplication.java:774)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:247)
at com.jme3.app.AndroidHarness.update(AndroidHarness.java:499)
at com.jme3.system.android.OGLESContext.onDrawFrame(OGLESContext.java:350)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1582)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1281)
2021-12-12 21:41:32.176 24222-24329/de.hc.jeep2d I/de.lessvoid.nifty.render.batch.BatchRenderImage: INFORMATION Image [de/lessvoid/nifty/render/batch/nifty.png] unloaded from texture atlas (atlas texture id: 1).
2021-12-12 21:41:32.176 24222-24329/de.hc.jeep2d I/de.lessvoid.nifty.render.batch.BatchRenderDevice: INFORMATION Switched atlases to atlas texture with id: 1.
2021-12-12 21:41:32.176 24222-24329/de.hc.jeep2d I/de.lessvoid.nifty.render.batch.BatchRenderImage: INFORMATION Image [Interface/hud.png] is not within atlas tolerance and has been created as a non-atlas texture (texture id: 3).
2021-12-12 21:41:32.188 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: Waiting for a blocking GC Alloc
2021-12-12 21:41:32.194 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: WaitForGcToComplete blocked Alloc on ProfileSaver for 5.601ms
2021-12-12 21:41:32.194 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: Starting a blocking GC Alloc
2021-12-12 21:41:32.202 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: Waiting for a blocking GC Alloc
2021-12-12 21:41:32.236 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: WaitForGcToComplete blocked Alloc on ProfileSaver for 33.846ms
2021-12-12 21:41:32.236 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: Starting a blocking GC Alloc
2021-12-12 21:41:32.239 24222-24242/de.hc.jeep2d E/System: Uncaught exception thrown by finalizer
2021-12-12 21:41:32.241 24222-24242/de.hc.jeep2d E/System: java.lang.NullPointerException: The native object does not exist.
at com.jme3.bullet.collision.shapes.CollisionShape.finalizeNative(Native Method)
at com.jme3.bullet.collision.shapes.CollisionShape.finalize(CollisionShape.java:233)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:289)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:276)
at java.lang.Daemons$Daemon.run(Daemons.java:137)
at java.lang.Thread.run(Thread.java:929)
2021-12-12 21:41:32.933 24222-24329/de.hc.jeep2d I/de.hc.jeep2d: Waiting for a blocking GC Alloc

Yes, I first tried the stable. After the errors occurs I tar.gz my lib directory and looked for newer versions. Because i haven’t a clue of the android studio, I just use a template from internet to make the projects from JME output.

Please put the stack trace inside code block so it would be easy to read.

As explained here Overview of memory management Android sets a hard limit on the heap size for each app. The exact heap size limit varies between devices based on how much RAM the device has available overall. For example, the device I use currently for testing is limited to 512Mb.
You can’t increase that limit, and you should make sure your app runs on low end devices.
I use the Android memory profiler to optimize that.

You can use the maxheap size available by adding the property android:largeHeap="true" but there are no guarantees it will really increase the memory, you should handle this from your game by decreasing the textures quality and the number of geometries or playing on level of details.

@vxel so I will call getMemoryClass somewhere in the code when I am running the app per adb, thanks!
@Pavl_G Becausw the app should only run on my Smartphone I will give this a try.

Does coincedently someone knows how much memory a terrain quad 2048*2048 will try to allocate?

Well, at a minimum that’s going to be 4 million elements just to keep track of the height.

I guess it’s doing some level of detail stuff but I don’t know enough about the terrain library anymore to know how it will break that up (nor what your setup is). But at high level of detail, each of those 4 million elements would be a vertex and ~2 triangles.

JME stats would say if you run it in desktop.

Also note, mesh and texture data will reside on native memory, not the heap memory. Though, I do not know if that is true in the case of Android.

I could not enable JME stat cause I use the guiNode and clear it every loop. So I use the jconsole after the I started the app in JME SDK:
while it stands in the nifty screen the heap Memory started at 10MB goes slightly upwards for approximately 2 minutes until 50MB then the garbage collector seems to start and the mem return to 10MB after I hit the start Button in Nifty and the terrain is created/inited the memusage increases to 250MB. During the game it moves betwwen 150MB and 230MB.

/me gasps in horror.

…clear it every loop. You very certainly unnecessarily do very bad things to your performance.

I just tested it with the memory profiler of the android studio within a 4G AVD.
During the Nifty display it run relative stable at 120 of 512 MB, At loading the terrain the out of memory is thrown at 460 of 512 MB,

I guess the next I try is a terainquad with 1024 by 1024 insted 2048*2048 and an doubled patchsize to keep the x/z scale.

The 1024 by 1024 try also brings out of memory exception maybe this evenning after work I will testing 512 by 512.

FYI: 512 by 512 loads on 4G AVD but stalls immediately (I got no Hardware Accelaration). On My 8G Smartphone it starlet also but runs very slow. Normaly the Apps on my Smartphone runs faster as on Desktop. Maybe I have to try 256 by 256 but I don’t think this will not look so fine on the terrain map I already scaled it by (8f, .6f, 8f) smoothed the height-map by 1f and set the patchsize to 4 to keep the streets drivable by the vehicle.

Light and filters can also contribute in slowing down your scene, the thing that slows down the game is multifactorial, you need also to ensure if there were objects that are keep spawning in a loop or something else like doing things on the Ui thread on the android side.

…like clearing the gui node and rebuilding it every frame… for example.

We still haven’t addressed that giant and 1000% unnecessary bad practice. Makes me wonder what other scary things might be going on.

1 Like

thanks for this broad hint. I am really thinking I could just update the tacho if the speed changed.