[SOLVED] Basic memory handling

Hello,

I have a very basic question about Memory usage.
I wrote a CAD-Program (computer aided design) that is loading files from disk and converts the data to meshes an geometries I attach to the rootNode.
When the user loads a new file from the disk I want to make sure that the allocated memory from the previous file is free again.
But when I use
app.rootnode.detachAllChildren();
it seems that the memory usage get’s higher every time I load a new file (info from task-manager).
Are there any other things I can do in the code to free memory.
Or can I monitor the memory usage in the JME IDE Debugger to find out why the memory used get’s more and more?
(I’m using IDE 3.5.2 and OpenJDK 11.0.17 )

1 Like

When you load a scene, the AssetManager caches the scene internally so that if you request the scene again, it will load faster. You should be able to disable caching by overriding the cache type on the AssetKey.

ModelKey key = new ModelKey("Models/MyModel.j3o") {
    @Override
    public Class<? extends AssetCache> getCacheType() {
        return null;
    }
};
Spatial model = assetManager.loadModel(key);
2 Likes

Might be better to clear the cache when you don’t want to keep stuff rather than disabling it.

It’s also a smart cache and so should still automatically free stuff when it’s not used anymore.

Note that task manager will lie to you. Java will request memory from the OS and never give it back. The only way to know for sure is to attach a profiler and see what the memory usage is. (Or attach jconsole which can tell you total memory… a profiler will actually give you details about what’s still in RAM.)

Asking the OS is never reliable.

5 Likes

Notice that, one of the reasons that might hinder the GC from doing its job on the unused memory, is keeping a hard reference to this memory somewhere in your code (e.g., a getter function), try to keep everything as local references as much as you can. While other reasons might be the uncontrolled loading of an asset in game loops, so check your scene tree, as well. Overall, jconsole or any Java profiler tool will give some insights, memory almost always needs to be profiled against time and events.

1 Like

Sorry, but I don’t load any j3o files. The complete Geometry is created by code. I’m just filling the buffers and create the meshes and Geometries that I attach to the rootNode.

m = new Mesh();
m.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
m.setBuffer(VertexBuffer.Type.Normal,3, BufferUtils.createFloatBuffer(nb));
m.updateBound();
m.setStatic();
Geometry geom = new Geometry(iD, m);
someNode.attachChild(geom); 

I don’t know what you mean with the “getter” function.
I have many classes that have a getMesh() method where the meshes are created.
And I have a tree of nodes. So there are many nodes and geometries that are not directly attached to the rootNode but like this
rootNode - nodeA — nodeB — nodeC
| | |
nodeD GeomA GeomB
|
GeomC
Am I right when I say it should be enough to detach all Children from the rootNode to cleanup?

If you are keeping this reference to the mesh, then that will prevent the GC from freeing up the memory.

To effectively clear a spatial’s memory, you need to both detach it from the scene and also clear all potential references to it (in this case you should set m = null somewhere where you do cleanup, or make Mesh m a local variable rather than a class variable so you aren’t holding a reference to it).

Thank you very much. I understand.
But now I have to check 150.000 lines of code for those references.
That’s really learning it the hard way.

3 Likes

What is happening if I always use the same static reference for different meshes? Example:

m = new Mesh();
// create static Geometry and attach it to a Node
m = new Mesh();
// create static Geometry and attach it to a Node
m = new Mesh();
// create static Geometry and attach it to a Node
m = new Mesh();
// create static Geometry and attach it to a Node
rootNode.detachAllChildren();

How many mesh-references do exist now in Memory?. It should be only one. Right?

Yes with that code it would only be holding a reference to (and preventing natural GC cleanup for) that one most recently stored mesh.

It is also important to make sure you clear references to any parent nodes that your geometry was attached to (assuming there are some other parent nodes between the geometry and the rootNode).

And also you may have to do some extra cleanup if you have any controls that are associated with a spatial, or anything similar. For example, holding a reference to something like an AnimComposer will also hold a reference to whichever spatial it was controlling.

1 Like

Why using a static reference, what’s the intention when the scene manager or the parent node could provide you with a reference whenever you need to manipulate something?

1 Like

One of the good design guidelines that I applause about the NASA’s C/C++ Coding Style is the favor of use of local references over the global references, I know this may be out of context, but in most cases, this is the emergence of memory leaks, in addition to the uncontrolled memory allocations, so despite working on Java and not Native code, you could still utilize this fact to improve your application. In that case, you don’t depend that much on GCs, you rely on the stack to get rid of references to help GCs implicitly do their work on memory.

EDIT:
And, btw, I still having some memory leaks on Android particularly the JmeSurfaceView and its dependencies; because of these…

1 Like

If m is a local variable within a method, you don’t even need that - it will clear down when the method terminates. Writing small methods to wrap this sort of detail is good software hygiene.

1 Like