Reloading TerrainQuad leads to OutOfMemoryError

Hello everyone!

I have a problem with creating new and deleting old TerrainQuad classes. The idea is that I create one such class with texture and heightmap, and later I would like to destroy this instance of TerrainQuad (to recover memory) and create new one with new texture and heightmap. Both images (texture and heightmap) are 2048x2048 pixels as I am interested in detailed 3d map model.

I’m creating terrain in this way:
[java]mTerrain = new TerrainQuad(“terrain”, 65, heightmap.getSize(), heightmap.getHeightMap());[/java]
Later I add LOD control, material, scale, etc.

Then, when I want to create a new TerrainQuad I call the following function:
[java]
private void clearData()
{
try
{
rootNode.detachChild(mTerrain);
mTerrain.removeControl(mTerrainLodControl);
mTerrain.forceRefresh(true, true, true);
mTerrain.setMaterial(null);
mTerrain.detachAllChildren();
mTerrain = null;
System.gc();
}
catch (Exception e)
{
e.printStackTrace();
}
}
[/java]

So whenever I create TerrainQuad again, everything should be fine. But isn’t. Although I tried to set everything to null in mTerrain, there are still quads and patches in the memory (I used VisualVM to dump heap to read this information). As a result, after a few changes of the 3d map, I get OutOfMemoryError.
For better visualization of this problem: some numbers of instances after a few changes of the terrain:
floats[]: 4992 (53.8% size of heap -> 8744 (68.4%) -> 12496(72.2%)
quads: 1024 -> 2048 -> 3072
patches: 341 -> 681 -> 1021

In Task Manager after lunching the application it uses about 850MB, but after one change it jumps to more than 1GB and it crushes when reaches 1.4-1.6 GB.

So my question is: is there any way to have access to those unused fields to delete them? Garbage Collector doesn’t seem to be doing it’s job well in this case. Or is there any other way to set new heightmap to the terrain (creating two ‘for’ loops to use setHeight method doesn’t sound good for me, besides there might get some unwanted artifacts)?

In the end I will also add, that setting LOD control to null and disabling it, so later it is possible to start fresh instance for new terrain, doesn’t stop “jME Terrain Thread”. Again, thanks to Thread Dump in VisualVM I was able to find it. Fortunately, it is possible to create one LOD Control and just set new terrain there.

If there was any topic related to this problem: sorry, as you can see, I am brand new on this forum :wink:

PS. I tried also to create a loop to search for all children of children of TerrainQuad and remove them from parent one by one, but it still doesn’t work.

edit:
The error output is the same as in the topic http://hub.jmonkeyengine.org/forum/topic/application-crashes-in-sdk-but-not-out-of-sdk/, but I am sure that I use 64-bit JVM, as this one is the only one set in my Eclipse (yes, I use this IDE). Anyway, if I export the project to runnable jar, the error still exists.

To clean up the memory of the terrain you just have to detach it from the root node. So you must be holding onto a reference to it somewhere. Also calling System.gc() does not guarantee to actually clean it up. Detaching the terrain also removes any controls it has set on it (LOD Control).
Also, a terrain that is 2048x2048 has 4.2million vertices. Then for each vertex you have the normal, tangent, binormal vectors, and texture coordinate (11 floats). I am dubious of your float count of 4992.
Unfortunately I will be away on holidays for two weeks starting in a few hours, so I won’t be able to help you further until I get back. I’m sure someone else can hop on this thread though and lend a hand.

Thanks for your reply!

Yes, I’m aware that I need to detach it from the root node, what I’m actually doing. This 4992 floats are used all around the project, I wanted only to present how their number is rapidly icreasing after 1-2 and 3-4 terrain reloads. So they are somewhere, but can’t be released. I look forward to any other reply.

You have shown some proficiency with heap dumps. That’s good !

Have you looked at what is holding all those references ? It may help you point-pinning the leak.
If you are able to find where all these references are attached to you project, you probably will know how to get rid of them. (if they are not useful)

I checked all references, but I don’t think it is this problem.

I tried to reproduce the error on the TerrainTest example without any LodControl to make it simpler.
[java]
private void createTerrain()
{
if (terrain != null)
{
rootNode.detachChild(terrain);
terrain = null;
System.gc();
}

    Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
    
    AbstractHeightMap heightmap = null;
    try {
        heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 1f);
        heightmap.load();

    } catch (Exception e) {
        e.printStackTrace();
    }
    
    terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
    terrain.setMaterial(matRock);
    terrain.setLocalTranslation(0, -100, 0);
    terrain.setLocalScale(2f, 1f, 2f);
    rootNode.attachChild(terrain);
}

[/java]

So this method is called in the simpleInitApp() and later whenever I press a button. It doesn’t run out of memory so fast (smaller images), but eventually, after dozens of calls, the error occurs. Well, the truth is that no one will probably try to reload the terrain so fast. The good thing is that Garbage Collection works, so it released memory after some time (number of quads and patches was still increasing, but slower than in my case).
The fastest solution in my problem is just to put the thread to sleep for about 5 second to give time for GC. It is a bit harsh, but at least it works (for now). If there is any way to solve it somehow, I would really appreciate giving me some more advice.