内存泄漏。不断上升直到游戏崩溃

Memory Leakage. Constantly rises until game crashes

我是 android 开发的新手,我遇到了关于我的游戏所用内存的问题。它不断上升直到崩溃。如果你能帮助我,我将不胜感激。谢谢。

此外,关于 Spritebatch,我是否需要在扩展到游戏的 java class 中调用 this.dispose 来处理它?如果是这样,我可以在哪里调用它?谢谢

public class Zero implements Screen, InputProcessor {
    Pmacgame game;
    private Stage stage;
    private Skin skin;
    private Sound sound ,laser;
    private Music musicbg;
    private Sprite spritebg, playerImage;
    private ImageButton imgbtnLeft, imgbtnRight, fire, color1, color2, color3, color4,
                        bullet1, bullet2, bullet3, bullet4;
    public static final float fireDelay = 0.3f;
    String rr2;
    private static int o = 0;

    Rectangle player;
    ArrayList<Bullet> bullets;
    ArrayList<Target> targets;
    ArrayList<Explode> explodes;
    //long lastDrop;
    int score;
    boolean a, b;
    public static final float minSpawnTime = 0.5f;
    public static final float maxSpawnTime = 1.25f;
    float shootTimer, targetSpawnTimer;
    Random random;
    public static int select;
    public static int dis = 0;
    public float health = 1;
    private Sprite greenBar, redBar, blueBar, pinkBar, greenBarO, redBarO, blueBarO, pinkBarO;
    public Zero(Pmacgame game){



    @Override
    public void render(float delta) {

        shootTimer += Gdx.graphics.getDeltaTime();
        ArrayList<Bullet> bulletsToRemove = new ArrayList<>();

            if (fire.isPressed() && shootTimer >= fireDelay) {
                shootTimer = 0;
                bullets.add(new Bullet(player.x + 32f));
            }


            for (Bullet bullet : bullets) {
                bullet.update(Gdx.graphics.getDeltaTime());
                if (bullet.remove)
                    bulletsToRemove.add(bullet);
            }

        targetSpawnTimer -= Gdx.graphics.getDeltaTime();
        if (targetSpawnTimer<=0){
            targetSpawnTimer = random.nextFloat() * (maxSpawnTime -minSpawnTime) + minSpawnTime;
            targets.add(new Target(MathUtils.random(267, Gdx.graphics.getWidth()-350f)));
        }
        ArrayList<Target> targetsToRemove = new ArrayList<>();
        for (Target target: targets){
            target.update(delta);
            if (target.remove)
                targetsToRemove.add(target);
            if (target.getY()<=0){
                health -= 0.1f;
                if (health<=0){
                    select = 0;
                    dis = 1;
                    this.dispose();
                    game.setScreen(new GameOverScreen(game, score));
                    return;
                }
            }
        }


        ArrayList<Explode> explodesToRemove = new ArrayList<>();
        for (Explode explode: explodes){
            explode.update(delta);
            if (explode.remove)
                explodesToRemove.add(explode);
        }
        explodes.removeAll(explodesToRemove);

        for (Bullet bullet: bullets){
            for (Target target: targets){
                if (bullet.getCollisionRect().collidesWith(target.getCollisionRect())){

                    targetsToRemove.add(target);
                    bulletsToRemove.add(bullet);
                    score+=5;
                    explodes.add(new Explode(target.getX(), target.getY()));
                    sound.play(1f, 1.3f, 0f);
                }
            }
        }

        targets.removeAll(targetsToRemove);
        bullets.removeAll(bulletsToRemove);

        //Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        game.batch.begin();
        spritebg.draw(game.batch);
        game.batch.draw(blueBarO, 0, 575, blueBarO.getWidth(), blueBarO.getHeight());
        game.batch.draw(redBarO, 0, 550, redBarO.getWidth(), redBarO.getHeight());
        game.batch.draw(greenBarO, 0, 525, greenBarO.getWidth(), greenBarO.getHeight());
        game.batch.draw(pinkBarO, 0, 600, pinkBarO.getWidth(), pinkBarO.getHeight());
        game.font.draw(game.batch, "SCORE: " + score, 40, Gdx.graphics.getHeight() - 40 );
        for (Bullet bullet: bullets){
            bullet.render(game.batch);
        }
        for (Target target: targets){
            target.render(game.batch);
        }
        for (Explode explode: explodes){
            explode.render(game.batch);
        }
        if (health == 0) greenBar.setSize(greenBar.getWidth(), 0f);
        game.batch.draw(greenBar, 0, 525, greenBar.getWidth() * health, greenBar.getHeight());
        game.batch.draw(redBar, 0, 550, redBar.getWidth(), redBar.getHeight());
        game.batch.draw(blueBar, 0, 575, blueBar.getWidth(), blueBar.getHeight());
        game.batch.draw(pinkBar, 0, 600, pinkBar.getWidth(), pinkBar.getHeight());
        game.batch.draw(playerImage, player.x, player.y, player.width, player.height);
        game.batch.end();


        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
        if (a) player.x -= 450 * Gdx.graphics.getDeltaTime();
        if (b) player.x += 450 * Gdx.graphics.getDeltaTime();
        if (player.x < 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth())
            player.x = 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth();
        if (player.x > Gdx.graphics.getWidth() - 350f)
            player.x = Gdx.graphics.getWidth() - 350f;
    }

    @Override
    public void dispose () {
        musicbg.dispose();
        laser.dispose();
        stage.dispose();
        skin.dispose();
        sound.dispose();

    }

}

public class Pmacgame extends Game {
    SpriteBatch batch;
    BitmapFont font;

    @Override
    public void create () {
        batch = new SpriteBatch();
        font = new BitmapFont(Gdx.files.internal("r.fnt"));

        this.setScreen(new Zero(this));


    }


    @Override
    public void render () {
        super.render();

    }

    @Override
    public void dispose() {
        font.dispose();
        batch.dispose();
    }


}

我在看字里行间,但看起来您必须在 Bullet/Target/Explosion 的构造函数中加载一个 Texture,因为我没有看到您将 Texture 或 TextureRegion 引用传递给它们的构造函数或render 方法。

您应该在单个 class 中加载所有纹理,并将对游戏对象的引用传递给 "borrow" 并使用它们进行绘制。否则,您将无缘无故地加载相同图像的许多副本。

此外,纹理是一次性的,这意味着它使用本机内存,并且在让垃圾收集器接收它之前必须调用 dispose()。否则,本机内存泄漏。

在你的情况下,所有这些子弹、目标和爆炸都在一遍又一遍地加载许多纹理,并且在你删除它们时从不丢弃它们。

关于您关于 SpriteBatch 的问题。是的,您应该在实例化它的同一个 class 中处理它,dispose() 是正确的地方。

编辑,准系统示例:

public class Assets implements Disposable {

    public final Texture horse;
    public final Texture bullet;
    // etc.

    public Assets (){
        horse = new Texture("horse.png");
        //...
    }

    public void dispose(){
        horse.dispose();
        //...
    }
}

public class Zero implements Screen, InputProcessor {
    private final Assets assets;
    //...

    public Zero (){
        assets = new Assets();
        //...
    }

    //...

    public void dispose(){
        assets.dispose();
        //...
    }
}

public class Bullet {
    //...

    public void render(SpriteBatch batch, Assets assets){
         batch.render(assets.bullet, /*...*/);
    }
}