Safely Deleting Image/Texture

Hello,
I am generating a lot of textures on the fly. By a lot I mean in the 1000s. These textures are heightmaps rendered for a specific quad in a quad tree. When I delete a quad I expected the texture to be garbage collected as no references to it are really left over. Yet this is not the case and the textures build up until things start moving very slowly. To fix this problem I attempted the following in the code section where the quad is deleted:
[java]
Image img1 = q.children.get(0).Heightmap.getImage();
Image img2 = q.children.get(1).Heightmap.getImage();
Image img3 = q.children.get(2).Heightmap.getImage();
Image img4 = q.children.get(3).Heightmap.getImage();
if(img1.getId() != -1){
renderManager.getRenderer().deleteImage(img1);
}
if(img2.getId() != -1){
renderManager.getRenderer().deleteImage(img2);
}
if(img3.getId() != -1){
renderManager.getRenderer().deleteImage(img3);
}
if(img4.getId() != -1){
renderManager.getRenderer().deleteImage(img4);
} [/java]
And this works…most of the time. Every now and then I get the program crashes and I am given the following error:
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalArgumentException: This NativeObject is not registered in this NativeObjectManager
at com.jme3.util.NativeObjectManager.deleteNativeObject(NativeObjectManager.java:136)
at com.jme3.util.NativeObjectManager.deleteUnused(NativeObjectManager.java:188)
at com.jme3.renderer.lwjgl.LwjglRenderer.onFrame(LwjglRenderer.java:767)
Which could mean that I am attempting to delete an image that has already been garbage collected…
Is there any way to do delete the texture safely?

yeah basicaly the default removal procesdure now makes a double delete.

Fr now you can only use System.gc() savly to force a collection.

This is one of the things I would really like to see, a safeguard agasint double deletions, allowing for manual memory disposal in some special cases, where necessary

@Empire Phoenix said: yeah basicaly the default removal procesdure now makes a double delete.

Fr now you can only use System.gc() savly to force a collection.

This is one of the things I would really like to see, a safeguard agasint double deletions, allowing for manual memory disposal in some special cases, where necessary

Calling System.gc() once every 60 frames (for performance reasons) does not fix the problem…the texture count keeps ramping up.
So what is the problem with how jmonkey handles the garbage collection of textures?

i dont think removing the reference would result in a perfomance boost, if anything itd hurt the perfomance.

the only drawback of it still being in memory is that it consumes more space in memory.

@icamefromspace said: i dont think removing the reference would result in a perfomance boost, if anything itd hurt the perfomance.

the only drawback of it still being in memory is that it consumes more space in memory.


If there wasn’t a performance boost from having 250 textures in memory compared to 2000 than I wouldn’t have made this post. When I delete the textures there is no performance lost and I am able to fly around indefinitely compared to memory being eaten up and the program stuttering to a crawl when I don’t.

the way java works is it reserves a “heap” of memory for your program. it micro manages deleting old objects based on how much memory is available/used/about to be used. Optimal perfomance would be to never delete memory as that requires processor time (assuming infinite ram is available)

if using a lot of memory is causing your application to slow down its likely because youre at your memory limit and garabage collection is going rampant removing every little unused object it possible can, btw jmonkey doesnt have any direct control over garbage collection. garbage collection is handled by the JVM period. System.gc() doesnt even guarantee garbage collection, its merely a suggestion for the jvm to do it.

Rather than trying to get your program to garbage collect EVEN MORE, you should probably consider how you could optimize your data, allow it to be cached and reused. or if you have the option, you could allocate more heap space to your application.

@icamefromspace said: the way java works is it reserves a "heap" of memory for your program. it micro manages deleting old objects based on how much memory is available/used/about to be used. Optimal perfomance would be to never delete memory as that requires processor time (assuming infinite ram is available)

if using a lot of memory is causing your application to slow down its likely because youre at your memory limit and garabage collection is going rampant removing every little unused object it possible can, btw jmonkey doesnt have any direct control over garbage collection. garbage collection is handled by the JVM period. System.gc() doesnt even guarantee garbage collection, its merely a suggestion for the jvm to do it.

Rather than trying to get your program to garbage collect EVEN MORE, you should probably consider how you could optimize your data, allow it to be cached and reused. or if you have the option, you could allocate more heap space to your application.

What is probably happening is jmonkey is sending the underlying opengl driver the texture and when, on the java side of things, the texture is garbage collected jmonkey is not “notifying” the opengl that the texture is no longer in use so it sticks around… That’s the only thing that really makes sense.

And I think handling a potential memory leak is pretty high on the list of optimizations that could be made.

Also, here is the heap usage for my program when it starts slowing down and the texture count is around 2200:

It would be interesting to know what the direct memory usage is. Normally I expect objects to eventually be freed (even the native ones like textures) unless there is a reference still being held.

Still, given your heap usage, if your direct memory usage is still at default then you will run out pretty fast as a GC won’t be triggered and the direct memory won’t be freed. I’m not saying that’s your issue because there seem to be other things in play. I don’t know if a System.gc() fixed the performance problem or not. I think not but I guess the texture count may be wrong for other reasons and it wasn’t clear if the performance problem still existed.

I’m going to guess yes.

It certainly sounds like something is still holding a reference. How do you create the textures?

@pspeed said: It would be interesting to know what the direct memory usage is. Normally I expect objects to eventually be freed (even the native ones like textures) unless there is a reference still being held.

Still, given your heap usage, if your direct memory usage is still at default then you will run out pretty fast as a GC won’t be triggered and the direct memory won’t be freed. I’m not saying that’s your issue because there seem to be other things in play. I don’t know if a System.gc() fixed the performance problem or not. I think not but I guess the texture count may be wrong for other reasons and it wasn’t clear if the performance problem still existed.

I’m going to guess yes.

It certainly sounds like something is still holding a reference. How do you create the textures?

Yea calling System.gc() did not fix the problem.

When there are 1000s of textures:
Total heap memory held: 70600kb
Total direct memory held: 49299kb

I create the textures like so:
[java]
Texture2D hm = new Texture2D(itexSize, itexSize, Format.RGBA32F);
FrameBuffer fbo = new FrameBuffer(itexSize, itexSize, 1);
fbo.setColorTexture(hm);
[/java]
Now each quad takes the heightmap texture as an argument yet when a quad is no longer in use it is removed from the scene and the list where all quads are located effectively removing all references to it. The viewport that the framebuffer using the texture as a target is attached to is removed from use also and the framebuffers are effectively garbage collected…
I can’t find any references to the texture that I am not cleaning up…

Have you run it in the memory profiler to see if anything is still holding a reference?

What if you call http://hub.jmonkeyengine.org/javadoc/com/jme3/texture/FrameBuffer.html#clearColorTargets() on the framebuffer when you are done?

@pspeed said: Have you run it in the memory profiler to see if anything is still holding a reference?

What if you call http://hub.jmonkeyengine.org/javadoc/com/jme3/texture/FrameBuffer.html#clearColorTargets() on the framebuffer when you are done?


The memory profiler doesn’t show anything keeping a reference to it.
Clearing the color buffer does not work help.
This is the exact method that creates the texture:
[java]
public Texture2D getHeightMap1(int t , AssetManager assetManager, ViewPort vp, float TEXTURE_SIZE, QuadMesh currQuad){
Texture2D hm = new Texture2D(itexSize, itexSize, Format.RGBA32F);
FrameBuffer fbo = new FrameBuffer(itexSize, itexSize, 1);
fbo.setColorTexture(hm);
vp.setOutputFrameBuffer(fbo);
Quad q = new Quad(2,2);
Material mat = new Material(assetManager, “NoiseMaterial.j3md”);
mat.setInt(“t”, t);
mat.setFloat(“Size”, currQuad.width);

mat.setTexture(“cellRandTex”, cellTex);
Geometry geo = new Geometry(“Mesh”,q);
geo.setMaterial(mat);
vp.attachScene(ge1);
if(vp.isEnabled()){
geo.updateGeometricState();
}
return hm;
}
[/java]
The viewport is handled like so:

[java]
if(mainClass.getRenderManager().getPreViews().size() > i && o > 2){
ViewPort vp = mainClass.getRenderManager().getPreViews().get(i);
vp.clearScenes();
mainClass.getRenderManager().removePreView(vp);
}
[/java]
which also ensures that the framebuffer object is garbage collected.
I’ve searched for anything that may keep the texture alive but I have obviously been unsuccessful…
Thanks

So… your texture is a framebuffer? see here:
http://hub.jmonkeyengine.org/forum/topic/are-filters-never-cleaned-up/

Guys … use dispose():
http://hub.jmonkeyengine.org/javadoc/com/jme3/util/NativeObject.html#dispose()

If you don’t lose it, you will lose it.