Mastering libGDX AssetManager: Async Loading, Memory Management, and Common Pitfalls
Use libGDX’s AssetManager to load textures, sounds, and custom assets asynchronously, keep GPU memory tidy, and avoid frame drops. This guide shows a full usage pattern, custom loader example, and common pitfalls to watch for.
20 Sept 2025, 12:39 UTC

Why AssetManager Matters
When a game loads a texture, sound, or font, the call to new Texture("image.png") blocks the main thread until the file is read and the GPU memory is allocated. In a fast‑moving game loop this can cause noticeable frame drops or even a temporary freeze. AssetManager solves this by queuing load requests, performing the work on a background thread, and letting the main thread continue rendering. It also keeps a reference count for each asset so you can unload resources you no longer need, preventing GPU memory leaks during level transitions.
Typical Usage Pattern
- Instantiate once and reuse. Create a single
AssetManagerin yourGamesubclass and pass it to everyScreen.public class MyGame extends Game { public static AssetManager assetManager; @Override public void create() { assetManager = new AssetManager(); setScreen(new LoadingScreen()); } } - Queue assets. In a loading screen or wherever you need the assets, call
load()with a path and the class type.AssetManager manager = MyGame.assetManager; manager.load("textures/hero.png", Texture.class); manager.load("sounds/jump.wav", Sound.class); - Poll progress. In the
render()loop of the loading screen, callmanager.update()untilisFinished()returns true, then transition to the next screen.public void render(float delta) { if (!manager.update()) { float progress = manager.getProgress(); // 0.0–1.0 // e.g., draw a progress bar here } else { setScreen(new MainMenuScreen()); } } - Retrieve assets. Once finished, use
manager.get()to obtain the loaded objects.Texture heroTex = manager.get("textures/hero.png", Texture.class); Sound jumpSound = manager.get("sounds/jump.wav", Sound.class); - Unload when done. When leaving a level or a screen that no longer needs an asset, call
unload()ordispose().manager.unload("textures/hero.png"); // frees GPU memory if no other references
Custom Loaders – Extending AssetManager
AssetManager can load any type that implements com.badlogic.gdx.assets.AssetLoader. For example, to load a JSON configuration file into a custom GameConfig object:
public class GameConfigLoader extends AsynchronousAssetLoader<GameConfig, JsonParameter> {
public GameConfigLoader(FileHandleResolver resolver) { super(resolver); }
@Override
public void loadAsync(AssetManager manager, String fileName, FileHandle file, JsonParameter parameter) {
Json json = new Json();
json.setIgnoreUnknownFields(true);
config = json.fromJson(GameConfig.class, file);
}
@Override
public GameConfig loadSync(AssetManager manager, String fileName, FileHandle file, JsonParameter parameter) {
return config;
}
}
Register it once:
manager.setLoader(GameConfig.class, new GameConfigLoader(new InternalFileHandleResolver()));
manager.load("config/game.json", GameConfig.class);
Limitations and Common Pitfalls
- No automatic unloading. AssetManager tracks reference counts, but you must explicitly call
unload()ordispose()for assets no longer needed. Forgetting to do so will grow GPU memory and can lead toGL_OUT_OF_MEMORYerrors. - Path consistency. Asset paths are case‑sensitive on most file systems. Mixing "Textures/hero.png" and "textures/hero.png" will cause the same file to be loaded twice, wasting memory.
- Thread safety. All
load(),get(), andunload()calls must happen on the rendering thread or be synchronized. Do not callAssetManager.update()from a background thread. - Direct loading bypasses AssetManager. Instantiating
new Texture("image.png")inside a screen’sshow()will block the main thread and bypass reference counting. Usemanager.load()instead. - Large assets and memory fragmentation. If you frequently load and unload many small textures, GPU memory can fragment. Keep a core set of assets loaded for the entire game and only unload large, level‑specific packs.
Practical Checks
After loading, you can verify that the asset is ready and that memory usage is as expected:
manager.isFinished()– true when all queued assets are ready.manager.getProgress()– visual progress bar value.manager.getReferenceCount("textures/hero.png")– should be 1 after a single load.- On Android, use
adb shell dumpsys meminfo <package>or theGLSurfaceViewdebug flags to inspect GPU memory.
When to Use AssetManager
Use it whenever you have:
- Multiple asset types (textures, sounds, fonts).
- Level transitions that require different asset sets.
- Any need to keep the main thread responsive during loading.
For very small, single‑screen prototypes, you might skip it, but for production code the benefits outweigh the learning curve.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.