MemoryLeak in NiftyGUI when element has an ID

Hi, :slight_smile:
I found out nifty gui seems to have a memory leak if an element has an id. Test case:

[java]package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.ViewPort;
import com.jme3.util.MemoryUtils;
import de.lessvoid.nifty.Nifty;

public class TestMemoryApplication extends SimpleApplication{

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

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

@Override
public void simpleInitApp(){
    ViewPort viewPort = renderManager.createPostView("niftygui", guiViewPort.getCamera().clone());
    viewPort.setClearFlags(false, false, false);
    
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort);
    viewPort.addProcessor(niftyDisplay);
    Nifty nifty = niftyDisplay.getNifty();
    nifty.addXml("Interface/test.xml");
    nifty.gotoScreen("start");
}

}[/java]

Here’s my test.xml-file:
[xml]<?xml version="1.0" encoding="UTF-8"?>











[/xml]

Notice, that if I add an id to the button, e.g. id=“abc”, the memory isn’t cleaned up properly after closing the application.

The output without id (using the above xml-file):

686139 bytes 686139 bytes 382472 bytes 8220 bytes 8220 bytes

When using an id:

686139 bytes 686139 bytes 680730 bytes 680730 bytes

No idea, why the leak is there. I even tried to call renderer.cleanup(), renderer.resetGLObjects(), removing the processors from the viewport, removing the button element from the screen, removing the screen from the nifty, etc. etc. but nothing fixed the problem. :frowning:

Yours, destro

Well, the Screen keeps a reference to all elements with the id as the key (which will make the referenced Elements not GCed). Usually when a screen ends (gotoScreen() or removeScreen()) these elements are unregistered with the screen again which should make them available to be GCed.

Can you post an example where you actually call removeScreen()? Because the example as it is above will always stay on the same screen and therefore will never free the elements with an id as long as the screen is active, I think.

[java]package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.ViewPort;
import com.jme3.util.MemoryUtils;
import de.lessvoid.nifty.Nifty;

public class TestMemoryApplication extends SimpleApplication{

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

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

@Override
public void simpleInitApp(){
    ViewPort viewPort = renderManager.createPostView("niftygui", guiViewPort.getCamera().clone());
    viewPort.setClearFlags(false, false, false);
    
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort);
    viewPort.addProcessor(niftyDisplay);
    nifty = niftyDisplay.getNifty();
    nifty.addXml("Interface/test.xml");
    nifty.gotoScreen("start");
}

@Override
public void destroy(){
    nifty.removeScreen("start");
    super.destroy();
}

}[/java]

I’m calling the removeScreen-method in the destroy-method, before the application gets closed (The line is called, I tested it with a println).

The used memory:

686155 bytes 686263 bytes 680846 bytes 680846 bytes