Memory management - garsue/libgdx GitHub Wiki

Games are resource heavy applications. Images and sound effects can take up a considerable amount of RAM. Also, most of these resources are not managed by the Java garbage collector. Instead they are managed by native drivers. Having the garbage collector decide when to release a 5 megabyte texture from video ram wouldn't be a too bright idea either.

We want fine grained control over the life-time of our resources. There are multiple classes in libgdx which represent such resources. They all implement a common Disposable interface which indicates that instances of this class need to be disposed of manually at the end of the life-time. Failure to dispose resources will lead to severe memory leaks!.

The following classes need to be disposed of manually (might not be complete):

  • AssetManager
  • Bitmap
  • BitmapFont
  • BitmapFontCache
  • CameraGroupStrategy
  • DecalBatch
  • ETC1Data
  • FrameBuffer
  • Mesh
  • Model
  • ModelBatch
  • ParticleEffect
  • Pixmap
  • PixmapPacker
  • Shader
  • ShaderProgram
  • Shape
  • Skin
  • SpriteBatch
  • SpriteCache
  • Stage
  • Texture
  • TextureAtlas
  • TileAtlas
  • TileMapRenderer
  • com.badlogic.gdx.physics.box2d.World
  • all bullet classes

Resources should be disposed of as soon as they are no longer needed, freeing up memory associated with them. Accessing a disposed resource will result in undefined errors, so make sure to clear out all references you have to a disposed resource.

When in doubt about whether a specific class needs to be disposed of, check if it has a disposed() method. If it does, you are now working with a native resource.

Object pooling

Object pooling is the principle of reusing inactive or "dead" objects, instead of creating new objects every time. This is achieved by creating an object pool, and when you need a new object, you obtain it from that pool. If the pool has an available (free) object, it is returned. If the pool is empty, or does not contain free objects, a new instance of the object is created and returned. When you no longer need an object, you "free" it, which means it is returned to the pool. This way, object allocation memory is reused, and garbage collector is happy.

This is vital for memory management in games that have frequent object spawning, like bullets, obstacles, monsters, etc.

Libgdx offers a couple tools for easy pooling.

Implementing the Poolable interface means you will have a reset() method in your object, which will be automatically called when you free the object.

Below is a minimal example of pooling a bullet object.

public class Bullet implements Poolable {

    public Vector2 position;
    public boolean alive;

    /**
     * Bullet constructor. Just initialize variables.
     */
    public Bullet() {
        this.position = new Vector2();
        this.alive = false;
    }
    
    /**
     * Initialize the bullet. Call this method after getting a bullet from the pool.
     */
    public void init(float posX, float posY) {
    	position.set(posX,  posY);
    	alive = true;
    }

    /**
     * Callback method when the object is freed. It is automatically called by Pool.free()
     * Must reset every meaningful field of this bullet.
     */
    public void reset() {
        position.set(0,0);
        alive = false;
    }

    /**
     * Method called each frame, which updates the bullet.
     */
    public void update (float delta) {
    	
    	// update bullet position
    	position.add(1*delta*60, 1*delta*60);
    	
    	// if bullet is out of screen, set it to dead
    	if (isOutOfScreen()) alive = false;
    }
}

In your game world class:

public class World() {

    // array containing the active bullets.
    private final Array<Bullet> activeBullets = new Array<Bullet>();

    // bullet pool.
    private final Pool<Bullet> bulletPool = new Pool<Bullet>() {
	@Override
	protected Bullet newObject() {
		return new Bullet();
	}
    };

    public void update(float delta) {
	
        // if you want to spawn a new bullet:
        Bullet item = bulletPool.obtain();
        item.init(2, 2);
        activeBullets.add(item);

        // if you want to free dead bullets, returning them to the pool:
    	Bullet item;
    	int len = activeBullets.size;
    	for (int i = len; --i >= 0;) {
    	    item = activeBullets.get(i);
    	    if (item.alive == false) {
    	        activeBullets.removeIndex(i);
    	        bulletPool.free(item);
    	    }
    	}
    }
}

The Pools class provides static methods for dynamically creating pools of any objects (using ReflectionPool and black magic). In the above example, it could be used like this.

private final Pool<Bullet> bulletPool = Pools.get(Bullet.class);
⚠️ **GitHub.com Fallback** ⚠️