Looking at the main GameMesh constructor (the one used for every downloaded building model):
public GameMesh(String name, Vector3 position, Vector3 rotation, Vector3 scale, btDynamicsWorld world) {
super(name);
this.world = world;
this.sceneAsset = ModelCache.acquire(name); // refcount incremented here
if (sceneAsset == null)
throw new IllegalArgumentException("Failed to load model: " + name);
this.instance = GltfModelFiles.buildInstance(sceneAsset, name, position); // can throw
this.bounds = instance.model.calculateBoundingBox(new BoundingBox());
this.bounds.mul(instance.transform);
this.body = createStaticBody(boxShapeFromModel()); // can throw too
world.addRigidBody(body);
}
ModelCache.acquire(name) increments the shared refcount for that building's model before the rest of construction runs. If GltfModelFiles.buildInstance(...) or createStaticBody(boxShapeFromModel()) throws partway through (malformed GLTF node, bad bounding box, whatever), the constructor throws and the GameMesh object never finishes being built. Since it never exists as a usable object, nobody can ever call dispose() on it, which is the only thing that calls ModelCache.release(name).
So that one acquire() just leaks. The cache's refcount for that building type is now permanently one higher than the number of real live instances, which means ModelCache.release() calls from every legitimate instance of that building will never bring the count to zero, and the shared model (and its GPU textures) never gets disposed for the rest of the app's life, even after the player deletes every instance of that building.
Would probably want a try/catch around the post-acquire construction that releases the reference back before rethrowing, something like:
this.sceneAsset = ModelCache.acquire(name);
if (sceneAsset == null) throw new IllegalArgumentException(...);
try {
this.instance = GltfModelFiles.buildInstance(sceneAsset, name, position);
...
} catch (RuntimeException e) {
ModelCache.release(name);
throw e;
}
File: core/src/com/focus/kingdom/entity/GameMesh.java, the constructor around line 98-114.
Looking at the main
GameMeshconstructor (the one used for every downloaded building model):ModelCache.acquire(name)increments the shared refcount for that building's model before the rest of construction runs. IfGltfModelFiles.buildInstance(...)orcreateStaticBody(boxShapeFromModel())throws partway through (malformed GLTF node, bad bounding box, whatever), the constructor throws and theGameMeshobject never finishes being built. Since it never exists as a usable object, nobody can ever calldispose()on it, which is the only thing that callsModelCache.release(name).So that one acquire() just leaks. The cache's refcount for that building type is now permanently one higher than the number of real live instances, which means
ModelCache.release()calls from every legitimate instance of that building will never bring the count to zero, and the shared model (and its GPU textures) never gets disposed for the rest of the app's life, even after the player deletes every instance of that building.Would probably want a try/catch around the post-acquire construction that releases the reference back before rethrowing, something like:
File:
core/src/com/focus/kingdom/entity/GameMesh.java, the constructor around line 98-114.