[Resolved] OgreODE demo memory leak?

ErgoSmurof

01-07-2009 18:14:08

Hello all,

I have been playing with: demos\ogreode\SimpleScenes.py, and am seeing what seems like a leak related to EntityInformer createStaticTriangleMesh. I tested this by adding the ability to remove the last added trimesh, and noticing that memory only ever increases -- it never seems to re-use memory from a previously allocated and freed trimesh.

Here's what I did:

- Added "deleteLastDroppedObject" function to SimpleScenes class (code shown at end).
- Added new key handler to SimpleScenes_BoxStack -- so that pressing "B" would invoke deleteLastDroppedObject. This lets me subtract objects from the scene.
- Added a bunch of trimeshes, then removed them all.
- Added a couple more.

Each time I add a trimesh, it consumes more memory. This happens regardless of whether I've just deleted enough of them that it should already have enough memory allocated to handle it. I realize fragmentation can be an issue, but I think there's more going on here than that. Do you see any problems in how I'm handling the deletion, or do you have any suggestions as to how I can debug this?

I am working on a publicly released commercial application that is being affected by out of control memory consumption, that I'm pretty sure I've narrowed down to OgreODE and my invocations of createStaticTriangleMesh.


Thanks!



def deleteLastDroppedObject(self):
if (self._key_delay < self.KEY_DELAY):
return 0

if [] == self._geoms:
return 0

geom = self._geoms.pop()
body = self._bodies.pop()
node = body.getParentSceneNode()
clearList = []
if node:
name = node.getName()
num = node.numAttachedObjects()
for cur in range ( num ) :
obj = node.getAttachedObject(cur)
print obj.getMovableType()
clearList.append(obj)
self._mgr.getRootSceneNode().removeAndDestroyChild(name)
self._space.removeGeometry(geom)
del body
del geom

## Remove all the entities we found attached to scene nodes we're controlling
for i in clearList:
if (i.getMovableType() == "Entity") :
print "Deleting " + str(i)
self._mgr.destroyMovableObject(i)
self._key_delay = 0.0

dermont

02-07-2009 03:12:45

It's been a while since I looked at this so I could be wrong but you appear to be adding the body to your clearList then trying to delete it, your program should crash really. Maybe try something like this for your clearList:


clearList+=[ node.getAttachedObject(j)
for j in range(node.numAttachedObjects())
if node.getAttachedObject(j).getMovableType() != body.getMovableType() ]
..

ErgoSmurof

03-07-2009 02:52:13

Thanks for the suggestion, dermont.

I changed the code to the following, but the problem persists.


def deleteLastDroppedObject(self):
if (self._key_delay < self.KEY_DELAY):
return 0

if [] == self._geoms:
return 0

geom = self._geoms.pop()
body = self._bodies.pop()
node = body.getParentSceneNode()
clearList = []
if node:
name = node.getName()
num = node.numAttachedObjects()
clearList = [node.getAttachedObject(j) \
for j in range(node.numAttachedObjects()) \
if node.getAttachedObject(j).getMovableType() != body.getMovableType()]
for i in clearList:
if (i.getMovableType() == "Entity") :
print "Deleting " + str(i)
self._mgr.destroyMovableObject(i)
self._mgr.getRootSceneNode().removeAndDestroyChild(name)

self._space.removeGeometry(geom)
del body
del geom

self._key_delay = 0.0

dermont

04-07-2009 12:47:25

I don't think this is a problem with your code, the same problem appears with the demos. It looks to be a problem with the python-ogre ogreode bindings, namely that the underlying C++ TriangleMeshGeometry destructor is never called which accounts for your memory leaks. Hopefully the developers can help you out.

ErgoSmurof

04-07-2009 13:30:12

Yep, I figured the same thing; that's why I posted here rather than in the C++ ODE section. I'm sure those generated bindings are really tricky beasts to deal with.

andy

06-07-2009 10:48:43

I've had a quick look at the OgreODE source code and it might be a bug in the TriangleMeshGeometry constructor where it's not setting _dataPtr to NULL.. And in the destructor it's checking for a Null _dataPtr before it frees vertex and index memory...

Could you possible send me your test program and I'll take a better look...

Also are you building your own PythonOgre or using the prebuilt binaries? I ask as I'm doing my current development with the SVN version (1.7.x) of Ogre and don't really plan on releasing another 1.6.x Windows Binary (doesn't stop others from doing so)

Thanks
Andy

dermont

06-07-2009 11:23:57

I've had a quick look at the OgreODE source code and it might be a bug in the TriangleMeshGeometry constructor where it's not setting _dataPtr to NULL.. And in the destructor it's checking for a Null _dataPtr before it frees vertex and index memory...

Could you possible send me your test program and I'll take a better look...

Also are you building your own PythonOgre or using the prebuilt binaries? I ask as I'm doing my current development with the SVN version (1.7.x) of Ogre and don't really plan on releasing another 1.6.x Windows Binary (doesn't stop others from doing so)

Thanks
Andy


@andy I don't think it is related to dataPtr being null. In C++ it works fine. As far as I can see, using debug statements, the destructor is just never called. You can test with the existing demos. From the SimpleScenes demo select the tri-mesh option then F1 for the BoxStack demo, select the debug option and you will see tri-mesh debug info is still there. I came across this problem some time ago but I can't remember how I resolved it (handwrapping the constructor ?)

ErgoSmurof

06-07-2009 14:19:16

Thanks for reviewing this, andy. I've attached my modified OgreODE demo files (only the modified files are included, so you could unzip this into an existing "demos\ogreode" folder).

My changes to the demo were pretty simple -- I just added the ability to subtract/remove the last-dropped trimesh from the scene. The only code I didn't include above was the following, which I added to SimpleScenes_BoxStack.py:

elif (keyinput.isKeyDown(OIS.KC_T)):
body = self.createRandomObject(OgreOde.Geometry.Class_Convex) #TriangleMesh)
elif (keyinput.isKeyDown(OIS.KC_G)):
self.createRagDoll()
elif (keyinput.isKeyDown(OIS.KC_B)): # this part is new
self.deleteLastDroppedObject() # this part is new

ErgoSmurof

06-07-2009 14:28:29

Also are you building your own PythonOgre or using the prebuilt binaries? I ask as I'm doing my current development with the SVN version (1.7.x) of Ogre and don't really plan on releasing another 1.6.x Windows Binary (doesn't stop others from doing so)


I'm using pre-built binaries at this point; but I expect that merging a fix for this issue and building from source would be reasonable straightforward.

Glad to (hopefully) help improve Python-Ogre 1.7. :)

andy

16-07-2009 04:51:48

Fix for this is now in the SVN -- change to code_generators/ogreode/generate_code.py
## Functions that return objects we need to manage
FunctionsToMemoryManage=[\
'::OgreOde::EntityInformer::createStaticTriangleMesh',
'::OgreOde::EntityInformer::createSingleStaticBox',
'::OgreOde::EntityInformer::createSingleDynamicBox',
'::OgreOde::EntityInformer::createSingleDynamicSphere'
]
for cls in FunctionsToMemoryManage:
global_ns.mem_fun(cls).call_policies = call_policies.return_value_policy( call_policies.manage_new_object )

Basically needed to tell boost to manage the returned object and delete it when done with it..

Regards
Andy

ErgoSmurof

16-07-2009 20:37:22

Thanks, Andy.

ErgoSmurof

25-07-2009 20:41:57

Success!!! Just a quick follow up report on this:

- I followed the steps in the Windows [semi-]automated build sequence from the wiki.
- I had to rename the ode zip file name in the downloads folder, to include the string "-src" that was apparently expected.
- Used the very nice build automation system (I'm a SCons fan myself).
- I had to build OgreODE from VisualC, since the script was attempting to do so via the UNIX configure / build stuff.
- I had to monkey with some of the paths in the OgreOde *.vcproj files; apparently some kind of directory refactoring had taken place

But I eventually got what I needed compiling, and the memory leak is definitely fixed. Thanks for your quick and helpful response here, andy!