游戏是资源密集型的应用。 图像和声音效果可能占用大量的RAM。 此外,这些资源大部分不由Java垃圾回收器管理。 相反,它们由本地驱动程序管理。 让垃圾收集器决定什么时候从RAM释放5M的纹理也不是一个太明智的想法。
我们希望对我们资源的生命周期进行细粒度的控制。 libgdx中有多个类需要人为在生命周期结束时进行手动处理。 它们都实现了一个通用的Disposable 接口,它指出了这个类的实例需要在生命周期结束时手动处理。 未能处置资源将导致严重的内存泄漏!
以下类别需要手动处理(可能不完整):
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
一旦不再需要资源,就应该处理资源,释放与之相关的内存。 访问已被清理的资源将导致未定义的错误,因此请确保清除所有已处理资源的引用。
当有疑问是否需要处理特定的类时,请检查它是否具有从com.badlogic.gdx.utils的Disposable接口实现的dispose()方法。 如果是,您现在正在使用本地资源。
您可要clone LibGDX的源码来寻找更多本地资源的类.
对象池
与其每次都创建一个对象,我们可以创建一个对象池来重用非活动的对象,当你需要一个新的对象时,你可以从对象池中获取,如果对象池中存在未被使用的对象,那么对象池会将其返回,如果对象池不存在空闲的对象,那么对象池会创建一个新的对象并返回它,这样对象被反复利用有利于内存的管理.
这对于对象产生频繁的游戏(如子弹,障碍物,怪物等)的内存管理至关重要。
Libgdx提供了几个工具,便于创建对象池:
实现Poolable接口意味着您将在对象中具有一个reset()方法,当您释放对象时,该方法将被自动调用。
以下是汇集子弹对象的一个简单示例:
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.
*/
@Override
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;
}
}
在你的游戏逻辑中(控制类):
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);
}
}
}
}
Pools类提供静态方法来动态创建任何对象的池(使用Reflection Pool反射对象池)。 在上面的例子中,可以这样使用。
private final Pool<Bullet> bulletPool = Pools.get(Bullet.class);
如何使用对象池
Pool<>管理单一类型的对象。 对象通过调用obtain()方法从特定Pool获取实例,然后通过调用free()将其释放到Pool中。 池中的对象可以可选地实现Pool.Poolable接口(只需要存在一个reset()方法),在这种情况下,当池返回到池时,池将自动重置对象。对象按需分配(所以如果您从不调用获取,则池将不包含任何对象)。
您必须实现自己的Pool <>子类,因为newObject方法是抽象的。
对象池注意事项
提防对象池的对象引用泄露,如果对象在外部仍在使用,但是你调用了对象池的free()方法,会导致外部引用无效,如果对象在放入对象池中没有完全被重置,那么当再次获取的时候,获取到的对象可能会有细微的错误.
网友评论