Out of Memory - Direct Buffer

When I play my game over some time, I get the following error message:



java.lang.OutOfMemoryError: Direct buffer memory
        at java.nio.Bits.reserveMemory(Bits.java:633)
        at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:95)
        at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
        at com.jme.util.geom.BufferUtils.createByteBuffer(Unknown Source)
        at com.jme.util.TextureManager.loadImage(Unknown Source)
        at com.jme.util.TextureManager.loadTexture(Unknown Source)
        at com.jme.util.TextureManager.loadTexture(Unknown Source)
        at kanjigame.bot.KanjiBot.initBot(KanjiBot.java:62)



KanjiBot is a class that helds a node with a box, and the texture of this box is dynamically created (every bot has another Kanji [Japanese symbol] on it). There come new bots in, and bots are killed and removed. Else there is not much changing in the level, at least not regarding textures. First I thought, that I hold somewherre a reference, which prevents the killed bots from GC. Then I put this code in the bot class:


    public void finalize() {
       System.out.println("bot killed");
    }



...and it was executed -> the bots are really garbage collected. When they are killed, I do this:


node.removeController(...); //for all controllers
node.getParent().detachChild(node);



.. but obviously this is not enough to GC the texture. I can see in the task manager, how the java process increases by about 0.7 MB when a bot is killed and a new one comes in.

Of course, I hold no direct references to the texture or to the node.

Any ideas?

If the texture for the bot is a new texture ( it isnt used for every bot), then TextureManager will have cached it, you will need to remove the cached texture from Texture Manager yourself

My game has a few leaks still, but most textures are now removed with the aid of the following code,



public class TextureCleanup {

   private static TextureState ts;
   
   public static void cleanTexture(Spatial s) {
      ts = (TextureState)s.getRenderState(RenderState.RS_TEXTURE);
      if(ts != null)
          ts.deleteAll(true);
      if(s instanceof Node) {
         ArrayList<Spatial> children = ((Node)s).getChildren();
         if(children != null) {
            Iterator i = children.iterator();
            while(i.hasNext()) {
               cleanTexture((Spatial)i.next());   
            }
         }   
      }
      ts = null;
      
   }
}


Node extends spatial so it flexible

Im not sure if it needs to be modified to allow for other TextureState removal, but it takes out standard ones.

It really depends on your game as to whether or not a weak reference cache is desired.  For example, if you are spawning goblins and everytime the goblin is killed, the gc finds it is able to clean up the texture, it means that A. the clean up code will have to force a delete on the texture and B. when you spawn your next goblin, suddenly the texture has to be recreated.



What would be ideal is a means in TextureManager to set whether to use a weak ref and probably also some method you could call that would get rid of textures not currently in use so you could manage cleanup manually in a smart manner.