Hopefully someone can give me a little insight on this.
I have a JOGL application that appears to be leaking system memory. I can run the application and see that it uses less than 1 GB as reported by YourKit Java Profiler. This includes heap and non heap memory. You can see that garbage collections are happening normally. Number of loaded classes also stays consistent. The problem is that Windows will eventually run out of memory. You can see the Java process continue to use memory until the entire system freezes up (I've manage to use all 32 GB of system memory.) I can also completely shut down and dispose the "scene" and related GL animator and the memory is then freed up. Unfortunately this is a very large and complex application. I am also unable to share any source code (except for the support library that I built which is open source https://github.com/pnnl/svf .) |
Administrator
|
Hi
I don't use non free profilers and I'm not paid to sell them. There is a plugin for JVisualVM to visualize the direct memory footprint and it shows the heap usage (build-in) too. Eclipse MAT can be useful to find memory leaks. What is the remaining problem? Are you sure that you're able to dispose the native memory used by the direct NIO buffers? I can only give you some vague advises. Don't keep any reference on useless Java objects so that the garbage collector can do its job and release the native memory by yourself.
Julien Gouesse | Personal blog | Website
|
In reply to this post by Art B
Are you sure the problem isn't just windows? Maybe you cna try to run it on Linux and see if that gives more insight. |
The problem exists on Mac. It likely exists on Linux as well.
The garbage collector is doing its job as the Java heap gradually rises and falls. Here's the results from testing more yesterday afternoon: I ran the application until it ran out of memory on Windows and a Mac. I then opened a bunch of web pages and applications. This is where there are differences between the two systems. Windows released some of the shareable working set memory for use by these other applications. Eventually it freed around 10 GB for use. Mac did not. It just crashed. According to the profiler the java objects are getting dereferenced properly. In the application there are less than 100 direct byte buffers created. These buffers are reused and this number never grows while the application is running. As soon as the main "scene" is shutdown and disposed both Windows and Mac will instantly release the (20+ GB of) system memory. I'm going to try and hunt down the Visual VM plugin and see if that provides any insight. Thanks |
Administrator
|
How do you "shutdown" your scene?
Julien Gouesse | Personal blog | Website
|
There's no easy answer for that. I code very abstractly so you have to review logs or walk through running code to find out what really happens.
This is the top level scene in question: @Override public void dispose() { viewportListener.dispose(); optionsModel.removePropertyChangeListener(viewportListener); setDataModel(null); setSeriesListModel(null); super.dispose(); } which ultimately calls dispose on these classes in the heirarchy: https://github.com/pnnl/svf/blob/develop/svf-awt/src/main/java/gov/pnnl/svf/awt/scene/AwtPanelScene.java https://github.com/pnnl/svf/blob/develop/svf-awt/src/main/java/gov/pnnl/svf/awt/scene/AbstractAwtScene.java https://github.com/pnnl/svf/blob/develop/svf/src/main/java/gov/pnnl/svf/scene/AbstractScene.java |
I just noticed that I'm caching references to GLUT, GLU, and GL. Are these okay to cache or should I be creating or getting new references for each draw cycle?
|
Since it isn't tied to a specific system I guess the easy way "it's a driver problem" is not relevant :-)
And since we can't see the code and it isn't reproduced in a test case it's hard to help apart from generic shouts of encouragement. I ended up doing this in my code: gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, this.vbos[bufferIndex]); FloatBuffer fbVertices = Buffers.newDirectFloatBuffer(values); final int bufferSizeInBytes = values.length * Buffers.SIZEOF_FLOAT; this.totalBufferSizeAllocated += bufferSizeInBytes; this.metrics.counter(Constants.Metrics.GL.VERTEX_ARRAY_BUFFER_SIZE_ALLOCATED).inc(bufferSizeInBytes); gl.glBufferData(GL4.GL_ARRAY_BUFFER, bufferSizeInBytes, fbVertices, GL4.GL_STATIC_DRAW); I use a (dropwizard) metrics class to track the allocation of direct buffers and a similar "decrement" to track the buffers I had asked OpenGL to allocate. Helped me track down some loops that only allocated more and more OpenGL buffers. Maybe you could use something similar. |
The conversation so far has still been helpful.
The library was created to be able to render using immediate mode, vertex arrays, display lists, shaders, and or vbo's. The problem visualization renders using immediate mode or display lists (although some of the actors can be rendered using vbo's.) It presents the behavior both ways. I like your idea about tracking vbo metrics. I already have a utility for tracking other metrics related to performance and "correctness". I'll have to create one for vbo's as well. I'll see if I can set up a demo in the open source library that can exhibit the behavior. However, this could take a few days. Thanks |
Administrator
|
In reply to this post by Art B
I have found nothing that explicitly releases the native memory.
You mustn't cache GL instances. You can store them in local variables with a very limited scope but do nothing that would lead to store them globally. They can become invalid at any time between 2 display attempts.
Julien Gouesse | Personal blog | Website
|
It takes a bit of work to track the life cycle of actors in the scene. Is there a particular native resource that gets instantiated that you found that isn't apparent on how it gets released?
I'm currently working on making sure that the GL, GLU, and GLUT (which has a GLU reference) references are not kept around for more than one display cycle. |
Administrator
|
Yes, you should avoid passing Java arrays when you can pass NIO buffers and you should always pass direct NIO buffers.
You can look at the retained memory in JVisualVM to find the most heavy objects.
Julien Gouesse | Personal blog | Website
|
Free forum by Nabble | Edit this page |