Posts
Search
Contact
Cookies
About
RSS

libgdx and Bullet - preventing accidental leaks...

Added 17 Nov 2013, 5:02 p.m. edited 18 Jun 2023, 1:12 a.m.
Its all too easy when using Java to forget that old fashioned languages like C++ positively encourage bugs especially in regards to memory allocation. If you have only a small number of physics bodies in existence with little or no turn over, you'll probably never notice anything amiss. Many people use time consuming and complex Object reuse strategies, which might or might not be faster - its all too easy when optimizing something to actually make it slower if you're not careful. The old meme that Java is slow is a hangover from its very early days, and since then the GC (Garbage Collector) has been improved so much, that if you are allocating and destroying very large numbers of objects you can actually be running faster than if you recoded it in C++ (no really - try it) Anyway... I took my example code and gave it a good stressing :D alas I'd forgotten to dispose of a few things in the physObj's dispose method - but then if I'm honest I didn't really check it with large numbers of objects... By way of stressing the demo code basically I just "destroyed" any objects that fall below a certain height and create a bunch of new objects each frame. Its well worth having a look at VisualVM which is a great utility for seeing whats going on in the internals of the JVM. I'm checking the height of each object in the render loop as I'm already iterating all the objects and there is no point reiterating the list...
Iterator<physObj> it = physObj.physObjects.iterator();
while (it.hasNext()) {
  physObj pob = it.next();
  modelBatch.render(pob.modelInst, environment);
  if (pob.body.isActive()) {
    pob.modelInst.transform.mul(tmpM.setToScaling(pob.scale));
    pob.motionstate.getWorldTransform(tmpM);
    tmpM.getTranslation(tmpV);
    if (tmpV.y<-10) {
      it.remove();
      pob.dispose();
      //System.gc();
    }
  }
}
Looking at the last if statement this is where we actually "destroy" an object, its important to use the iterator to remove the object from the list of objects to avoid commodification. Removing the object from the list means we wont be rendering it, of course all the objects resources are still intact. So we then tell the object to dispose of its resources, once that's done assuming you don't have any other references to that particular object then eventually it'll be collected by the GC. You'll notice that there's a suggestion to the VM to do a collection, thats been commented out, you wouldn't normally do this its very inefficient! but its useful while you're checking out things with VisualVM. Now for the bug fix!
    public void dispose() {
        collisionWorld.removeRigidBody(body);
        body.dispose();
        shape.dispose();
        if (null != motionstate) motionstate.dispose();
        modelInst = null;
    }
First off you need to remove the rigid body from the collision world, otherwise bad things will happen next time you step the physics world! Having done that we can dispose of the body and shape, the motionstate isn't always used but if it has been we need to get rid of that too, for good measure we null the model instance... While you can sit in VisualVM for ages with an eagle eye on the heap, you're much better off checking each field of a method and checking that you have disposed of anything that might have a reference to a wrapped bullet resource. For a change of pace and because someone asked... here's how to "shoot" something in the direction the camera is facing
        tmpM.idt().translate(cam.position.x,cam.position.y,cam.position.z);
        physObj shot = new physObj(physObj.pType.SPHERE,tmpV.set(1f,1f,1f),1,tmpM);
        tmpV.set(cam.direction);
        tmpV.scl(30f);
        shot.body.setLinearVelocity(tmpV);
By first setting a temporary matrix to identity we can set it with just the position of the camera once created get a vector representing the direction the camera is facing and multiply (scale) it to make it larger, then you can use it to set the Velocity (speed) of the body. Its important to point out that you should normally not directly set the speed of a physics body, rather influence them via forces, however when you're first creating the object its okay to set it off with an initial velocity. No code this time as you should be able to fix what you're doing with the previous code from whats posted here! Enjoy! Ooops ! forgot you'll need to dispose() the body creation info, you can do this straight away in the constructor - no idea what I was thinking of when I bothered keeping it...