Hi,
quick question: for the kart racing game I am working on I am creating a new btDiscreteDynamics world for each race. I am currently having some problems with deleting a dynamics world (crashes somewhere in the destructor). For now I assume that I am doing something wrong and I will chase it for a while, but I am generally wondering about memory management: do I have to free all allocated objects (like btAxisSweep3, btSequentialImpulseConstraintSolver, rigid bodies, motion states for bodies, ...) myself? Or are any objects handled (esp. freed) internally?
When can I delete objects, e.g. btAxisSweep - immediately after the dynamics world was created (i.e. does bullet make a copy), or do I have to keep it till the end (i.e. delete it after deleting the world)?
Or would you generally recommend to have only one dynamics world, and just remove all btrigid objects for each new race?
Hope these questions are not too general.
Cheers,
Joerg
Memory management when frequently deleting dynamicsWorld
-
- Posts: 83
- Joined: Tue Oct 24, 2006 11:52 pm
- Location: Australia
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Memory management when frequently deleting dynamicsWorld
You should only delete what you allocate, see the BasicDemo for example.
In general, delete objects in reverse order of creation, for example see BasicDemo:
Hope this helps,
Erwin
By the way, there are some internal memory caches for collision pairs, contact points and so on. Those internal allocations are freed internally (all using btAlignedAlloc/btAlignedFree, some using pools or stack allocators to avoid fragmentation etc). Bullet 2.64 has a memory leak tool for internal SDK data allocations, run AllBulletDemos and select MemoryLeakChecker. This only applies to btAlignedAlloc/Free.
You have to deal with all those yourself.hiker wrote:do I have to free all allocated objects (like btAxisSweep3, btSequentialImpulseConstraintSolver, rigid bodies, motion states for bodies, ...) myself? Or are any objects handled (esp. freed) internally?
Unless stated otherwise, there is no copy made internally, so you should not delete them. When a rigid body is added to the world, you should not delete it, until you after you removed it.When can I delete objects, e.g. btAxisSweep - immediately after the dynamics world was created (i.e. does bullet make a copy), or do I have to keep it till the end (i.e. delete it after deleting the world)?
In general, delete objects in reverse order of creation, for example see BasicDemo:
Code: Select all
void BasicDemo::exitPhysics()
{
//cleanup in the reverse order of creation/initialization
//remove the rigidbodies from the dynamics world and delete them
int i;
for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject( obj );
delete obj;
}
//delete collision shapes
for (int j=0;j<m_collisionShapes.size();j++)
{
btCollisionShape* shape = m_collisionShapes[j];
delete shape;
}
//delete dynamics world
delete m_dynamicsWorld;
//delete solver
delete m_solver;
//delete broadphase
delete m_overlappingPairCache;
//delete dispatcher
delete m_dispatcher;
delete m_collisionConfiguration;
}
It is a good idea to delete the simulation and start from scratch for each race.Or would you generally recommend to have only one dynamics world, and just remove all btrigid objects for each new race?
Hope this helps,
Erwin
By the way, there are some internal memory caches for collision pairs, contact points and so on. Those internal allocations are freed internally (all using btAlignedAlloc/btAlignedFree, some using pools or stack allocators to avoid fragmentation etc). Bullet 2.64 has a memory leak tool for internal SDK data allocations, run AllBulletDemos and select MemoryLeakChecker. This only applies to btAlignedAlloc/Free.
-
- Posts: 83
- Joined: Tue Oct 24, 2006 11:52 pm
- Location: Australia
Re: Memory management when frequently deleting dynamicsWorld
Hi Erwin,
Thanks a lot!
Joerg
Ah thanks. I always looked at the VehicleDemo, where the memory is not freed (I know that this is not important for the demo, I just thought with me having problems deleting world at the end, perhaps I am doing something wrong in freeing the data structures).Erwin Coumans wrote:You should only delete what you allocate, see the BasicDemo for example.
Understood.Erwin Coumans wrote: Unless stated otherwise, there is no copy made internally, so you should not delete them. When a rigid body is added to the world, you should not delete it, until you after you removed it.
In general, delete objects in reverse order of creation, for example see BasicDemo:
...
OK, at least I was doing it the right way. OK, then I'll start debugging my problemErwin Coumans wrote:It is a good idea to delete the simulation and start from scratch for each race.
Thanks a lot!
Joerg
-
- Posts: 11
- Joined: Wed Dec 06, 2006 1:59 am
- Location: Chapel Hill, NC
Re: Memory management when frequently deleting dynamicsWorld
Hmm, is this a design decision? I've grown accustomed to using reference counted pointers to manage and pass around most non-time-critical allocated objects, making the bookkeeping of what is alive and what not more manageable. Of course, that means that you have to take this into account when writing your class destructors, not making any assumptions about who allocated what.Erwin Coumans wrote:In general, delete objects in reverse order of creation, for example see BasicDemo:
You make it sound that such assumptions *are* made in Bullet, therefore requiring you to delete in some particular order. I can see where this becomes a problem, e.g. when exceptions are thrown, or early exits are required and you don't know the current state of your program.
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Memory management when frequently deleting dynamicsWorld
Yes indeed, it was my choice to not use reference counting, and to leave it up to the user to allocate and de-allocate the public objects, mainly for its simplicity.ngaloppo wrote:Hmm, is this a design decision? I've grown accustomed to using reference counted pointers to manage and pass around most non-time-critical allocated objects, making the bookkeeping of what is alive and what not more manageable.Erwin Coumans wrote:In general, delete objects in reverse order of creation, for example see BasicDemo:
I think there are pros and cons for both reference counting and single ownership. It is a great topic for long discussions. I've used reference counting extensively in the past, so here are my reasons for not using it, and using single-owner ship and checking for null pointers instead.
1) Reference counting creates dependencies, checking for a null pointer doesn't.
I'm a big fan of keeping things simple, modular and re-usable, with as few dependencies as possible. Once you introduce reference counting (addRef/releaseRef), the reference counting headerfile propagates through many files and projects, making it more difficult to re-use small parts of the code. A similar problem (not being able to re-use code) occurs due to lack of standard math classes. For clean interfaces, I prefer using standard C types. This contradics the fact that I used C++ for the Bullet interface. Providing C++ opens up the library for more customizations/re-use/modification.
2) Reference counting looses control of memory usage.
In demanding applications, especially on consoles with limited memory, it is important to keep control and insight of memory usage. With reference counting it is not clear if/when memory is available. When you use the single ownership, it is clear when it is safe to delete all data in one stage. This is not just a local problem, but also a global problem cross modules. I've had a case where we had a C++ and Python object binding, mixing python reference counting to our C++ reference counting. Once users created a global python variable, referencing the C++ object, we couldn't terminate the python interpreter for that reason.
3) Reference counting has a large impact on the system, especially container classes and serialization and circular dependencies. When using single ownership and pointers, container classes simply store the pointer, and don't need to know about reference counting. This point is similar to point 1 by the way.
4) Reference counting can have an impact on the performance, due to many (recursive) addRef/releaseRef calls. Keeping strict rules for the object life time (a rigid body is always valid as long as it is added to the dynamics world, so within the SDK, no null pointer checks or releaseRef are needed).
5) Reference counting can be very errorprone for users.
It is not always clear to users which objects are reference counted, and what the dependencies are. Some pointers to objects needs a 'delete' and others need a 'releaseRef'. Simply checking for a null pointer, unless you are the owner is more manageable.
I agree with you, the user needs to know the state of the program. To make it a bit easier, Bullet doesn't use exception handling, nor run-time type information, and there are no early exits possible, you have to go through the standard process of destructing objects in the reverse order they got created.You make it sound that such assumptions *are* made in Bullet, therefore requiring you to delete in some particular order. I can see where this becomes a problem, e.g. when exceptions are thrown, or early exits are required and you don't know the current state of your program.
I agree it should be better documented that the responsibility to free objects is up to the owner/creator in the reverse order.
Does this clarifies things?
Erwin
-
- Posts: 141
- Joined: Mon Jul 02, 2007 5:12 pm
Re: Memory management when frequently deleting dynamicsWorld
Really? Why is this? I've been seeing some inconsistent strange behavior (mentioned here), but I just chalked it up to the fact that I'm on a console and haven't been able to set up a proper test bed in our engine. Are there any reproducible issues that emerge from adding and removing bodies from the same simulation across multiple races (sticking with the original example)?It is a good idea to delete the simulation and start from scratch for each race.
- Alex
Last edited by AlexSilverman on Thu Nov 08, 2007 3:55 pm, edited 3 times in total.
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Memory management when frequently deleting dynamicsWorld
If you want determinism/reproducability, it is better to create a new dynamics world, and create the objects in exactly the same order. Bullet maintains internal caches, and the order depends on the order that objects are added, moved and removed.AlexSilverman wrote:Really? Why is this? I've been seeing some inconsistent strange behavior (mentioned here), but I just chalked it up to the fact that I'm on a console and haven't been able to set up a proper test bed in our engine. Are there any reproducible issues that emerge from adding and removing bodies from the same simulation across multiple races (sticking with the original example)?Or would you generally recommend to have only one dynamics world, and just remove all btrigid objects for each new race?
- Alex
To give some background: the order in which the constraint solver iterates over the individual constraints has an impact on the result. This order depends on the order of the overlapping pair array. In a similar fashion, the contact points for each collision pair depends on the order each point gets added.
We should add some mechanism to clear/sort all internal caches (overlapping pairs, persistent contact points, warm starting values and so on) in a predictable manner, but that is outstanding. In the AllBulletDemos, you can notice the difference between re-starting a demo by pressing 'R' key (which destroys the demo and re-creates it), or using the space-key (which teleports objects back to the original location, and flushes some caches, but not exhaustively, and resets a random seed)
Hope this helps,
Erwin
-
- Posts: 141
- Joined: Mon Jul 02, 2007 5:12 pm
Re: Memory management when frequently deleting dynamicsWorld
I edited my original post, since I quoted the wrong bit, but it seems like you saw through my mistake. Your answer clears it up a lot though. I thought there were drifting values or something somehow. Good to know that's not the case
Thanks for the response.
- Alex
Thanks for the response.
- Alex
-
- Posts: 83
- Joined: Tue Oct 24, 2006 11:52 pm
- Location: Australia
Re: Memory management when frequently deleting dynamicsWorld
Hi all,
just in case that someone else has the same problem (crashes when deleting a dynamics world): in my case it was caused by inconsistent memory releases: rigid bodies where still included in the dynamics world, but the collision shapes had been freed - stupid mistake actually Hope that this bit of information might save someone debugging time
Thanks Erwin for your long explanation and reasoning for not using ref counting - highly appreciated.
Cheers,
Joerg
just in case that someone else has the same problem (crashes when deleting a dynamics world): in my case it was caused by inconsistent memory releases: rigid bodies where still included in the dynamics world, but the collision shapes had been freed - stupid mistake actually Hope that this bit of information might save someone debugging time
Thanks Erwin for your long explanation and reasoning for not using ref counting - highly appreciated.
Cheers,
Joerg
-
- Posts: 3
- Joined: Thu Aug 11, 2005 11:34 pm
Re: Memory management when frequently deleting dynamicsWorld
If I need to delete objects in reversed order how should I handle things like pickups and dynamically generated content?
Say I create 10 spheres and when I hit the thing I want to delete it.
Say I create 10 spheres and when I hit the thing I want to delete it.
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Memory management when frequently deleting dynamicsWorld
The reverse order applies to dynamics world , collision dispatcher, constraint solver, broadphase, collision objects (rigid bodies), collision shapes etc. Within the collection of rigid bodies, it doesn't matter which order, so you can just iterate over the bodies. Check the Bullet/Demos/BasicDemo to see an example of deleting objects in reverse order.roar wrote:If I need to delete objects in reversed order how should I handle things like pickups and dynamically generated content?
Say I create 10 spheres and when I hit the thing I want to delete it.
Hope this helps,
Erwin
-
- Posts: 3
- Joined: Thu Aug 11, 2005 11:34 pm
Re: Memory management when frequently deleting dynamicsWorld
I'll freely admit to not reading much of the code or documentation, I just went through some samples and the userguide...
Is the following correct?
Given that
- btRigidBody derives from btCollisionObject
- m_dynamicsWorld has a collection of btCollisionObjects, m_collisionObjects (Rigid bodies and other collision objects)
- Stuff in m_collisionObjects must be deleted in reverse order
Say I create a bunch of rigid bodies and keep their pointers in an array
can I then, when something happens, do (during simulation, not when exiting the program)
Is the following correct?
Given that
- btRigidBody derives from btCollisionObject
- m_dynamicsWorld has a collection of btCollisionObjects, m_collisionObjects (Rigid bodies and other collision objects)
- Stuff in m_collisionObjects must be deleted in reverse order
Say I create a bunch of rigid bodies and keep their pointers in an array
Code: Select all
{
btBoxShape* shape = new btBoxShape(btVector3(0.5f,0.1f,0.5f));
btTransform tm(btTransform::getIdentity());
btRigidBody* bodies[10];
for( int i=0; i<10; ++i )
{
bodies[i] = localCreateRigidBody(0.0f, tm, shape);
}
}
Code: Select all
{
btRigidBody* body = bodies[5];
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject( body );
bodies[5] = NULL;
}