Force Direct Memory Garbage Collect

Hey guys, :slight_smile:
I’m having the same problem as described in this thread: http://hub.jmonkeyengine.org/forum/topic/error-java-lang-outofmemoryerror-direct-buffer-memory/

There are multiple applications started from a swing client (one after the other, i.e. after the previous one was already closed) and the used direct memory is growing with each iteration. In the mentioned thread, it was suggested to just force a garbage collect when starting a new application (which makes perfectly sense).

Unfortunately, I wasn’t able to find a way to do this with the direct memory (The default gc (System.gc():wink: obviously doesn’t do the trick).
I hope you can help me out. :slight_smile:

Yours, destro

If system.gc does not the trick, you are leaking memory yourself. System.gc does collect all direct buffers if they are unused reliabley (at least on openjdk and oracle vm)

I’m closing the applications via the stop() method. I don’t store the applications or any of their objects somewhere else, honestly I don’t know where my fault is. :frowning:

Might be time to hit the memory profiler, then. For example, if you are still holding a reference to the application then you are still holding a reference to everything it is holding a reference to.

I created a little test case, it’s the simple “blue box”-application, which can be closed by pressing the x key.
Every 2 seconds, the used direct memory is printed:

[java]package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.util.MemoryUtils;

public class TestMemory extends SimpleApplication implements ActionListener{

public static void main(String[] args){
    TestMemory app = new TestMemory();
    app.start();
    new Thread(new Runnable(){

        @Override
        public void run(){
            while(true){
                try{
                    Thread.sleep(2000);
                }catch(Exception ex){
                    ex.printStackTrace();
                }
                System.out.println(MemoryUtils.getDirectMemoryUsage() + " bytes");
            }
        }
    }).start();
}

@Override
public void simpleInitApp(){
    Box b = new Box(1, 1, 1);
    Geometry geom = new Geometry("Box", b);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);
    rootNode.attachChild(geom);
    
    inputManager.addMapping("close", new KeyTrigger(KeyInput.KEY_X));
    inputManager.addListener(this, "close");
}

@Override
public void onAction(String name, boolean isPressed, float tpf){
    if(name.equals("close")){
        stop();
    }
}

}[/java]

When running this code, the amount of used direct memory stays the same after closing the application (In my case 606403 bytes). As you see, I’m not really holding a reference to this application instance or anything similar… I think, I’m either missing a huge point here or the renderer thingy doesn’t clean up everything.
Please forgive me my inexperience at memory-related things^^

I’ve searched that whole piece of source for a System.gc() call and I do not see it. Did I miss it? Or did you miss what was said already.

Direct memory is only freed when the garbage collector is run. If the garbage collector has no need to run then it won’t run unless you tell it to. The garbage collector only uses heap memory size to determine when to run.

… Wow, best testcase ever :smiley: I really forgot the gc(), thanks for noticing.
Ok, now it does indeed clean up a lot of direct memory: (Calling the gc right before the System.out every 2 seconds)

601673 bytes 599837 bytes 599837 bytes [close] 24956 bytes 8220 bytes 8220 bytes 8220 bytes

At least I now know by 100% that the memory leak is on my side and if I fix it, I can clean up the direct memory by calling System.gc(). Thanks everybody for helping me. :slight_smile:

Common leaks in java comes from not removed listeners

just as a quick ninja hint

To add to that ninja hint… non-static inner classes also contain a reference to their parent class instance. Since listeners tend to be either non-static declared inner classes or anonymous inner classes, they also carry their whole parent around with them. It can be insidious.