away3d / away3d-core-openfl

Away3D engine for OpenFL

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possible memory leak related to RemoveChild()

abpyles opened this issue · comments

I am working on a project that requires loading and unloading of models, and have been experiencing trouble with memory usage increasing over time. I believe I have it narrowed down to a problem with the RemoveChild() method in the ObjectContainer3D class. If I load a Model from a file into a Mesh object, then dispose of it, and do this repeatedly the memory usage of my application does not grow at all. However, when I load a model into a Mesh, put the Mesh in an ObjectContainer3D, remove it from the ObjectContainer3D, dispose of the Mesh, and do this multiple times the memory usage slowly goes up. Of course to display the Mesh I need to put it in an ObjectContainer3D, so I really need to get this issue figured out. Has anyone encountered this?

I have now made a post on the Away3D forums with some code to show the problem I am experiencing.http://away3d.com/forum/viewthread/5810/

I'll look into it. Thanks for the example showing the problem and I can recreate it. Also just tried with a simple Mesh with a PlaneGeometry using a high number of segments to allocate memory. If I dispose of the Mesh straight away it's ok but once added to the scene and rendered, dispose doesn't reduce the memory.

I'll investigate.

Thanks, After messing around with it some more I see it only leaks memory after the Mesh is rendered as you say. I've been doing some profiling of my application to see if I can find what is causing the leak. I don't know that much about the internal workings of Away3D, so I don't know if I'll be able to find anything of use, but I'll post it up if I do.
Thanks again for looking into this.

One thing I've noticed - especially with a simplified example but high poly count (e.g. Plane with 100x100 segments), is that the Geometry of the Mesh is not removed explicitly when the Mesh is disposed. This may naturally disappear in the normal GC eventually but I'm not that familiar with the GC process in general.

The reason for this is that Geometries can be shared across multiple meshes to improve performance by reducing buffer uploads to the GPU. As such the geometry object can persist.

To dispose of the geometry simply call mesh.geometry.dispose() prior to call to the mesh.dispose method(s). It certainly help in my example.

Here is some output BEFORE the geometry dispose:
Main.hx:69: 1:Base - no models :0.03
Main.hx:71: 2:Plane created :4.95
Main.hx:74: 3:Sphere created :7.72
Main.hx:77: 4:Plane added to scene :7.72
Main.hx:80: 5:Sphere added to scene :7.72
Main.hx:117: 6:About to remove plane :8.19

and here is the AFTER version:
Main.hx:69: 1:Base - no models :0.03
Main.hx:71: 2:Plane created :4.95
Main.hx:74: 3:Sphere created :7.72
Main.hx:77: 4:Plane added to scene :7.72
Main.hx:80: 5:Sphere added to scene :7.72
Main.hx:117: 6:About to remove plane :8.19
Main.hx:120: 7:Plane removed :3.26
Main.hx:123: 8:About to remove sphere:3.26
Main.hx:126: 9:Sphere removed :0.47

The mem is still not back to the original but the whole rendering is still in progress whereas it wasn't at step 0. Also, in your example, Loader3D's and ObjectContainer3D's (a loader extends a container) need to be handled a bit differently as you'ld need to iterate through the children to remove the geometries, so you have the loader and you are cloning it into a new mesh - so they will contain the shared geometry.

Let me know how you get on with adding the geometry.dispose() to see if that helps.

After adding the changes you mentioned, I think the memory issues are all but solved. If I force garbage collection after I dispose of everything, and then reload everything the memory usage stays almost exactly the same. It does still grow by a very small amount each time. I have tested my program with meshes ranging in size from 2 triangles to a few thousand, and the growth in memory usage is always the same. It's hard to get an exact measure, but it is at most a few bytes. So it is a pretty small leak, and it is definitely related to the rendering of the models. Even setting mesh.visible = false; so that the mesh is never rendered completely eliminates the leak, and allows me to load and unload the model hundreds of times without even a slight uptick in memory usage. I'll try to post up some code showing how I am implementing everything later.
Thanks again for helping me out with this.