You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LibGDX多屏幕冒险游戏崩溃排查:内存泄漏引发SIGSEGV

选择式冒险游戏的内存泄漏崩溃问题及解决

我正在开发一款选择式冒险游戏,每个游戏状态对应不同的Screen类,点击前一屏幕的按钮时创建对应Screen实例进行切换(类似Henry Stickman游戏但更简单),这是我的第一款正式游戏。

当前实现的两个Screen类代码

MarketScreen类

public class MarketScreen implements Screen {

    final Heist game;

    private final Texture backgroundImage;
    private final Music backgroundMusic;

    private Stage stage;
    private Table table;
    private TextButton button1;
    private TextButton button2;
    private TextArea text;

    private OrthographicCamera camera;

    public MarketScreen(final Heist game) {
        this.game = game;

        //load images (64x64 pixels)
        backgroundImage = new Texture("background.jpeg");

        //load sound effects and music
        backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal("ironLung.mp3"));
        backgroundMusic.setLooping(true);

        //create camera and spriteBatch
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);

        //stage setup
        stage = new Stage(new ScreenViewport());
        Gdx.input.setInputProcessor(stage);

        //table setup
        table = new Table();
        table.setFillParent(true);
        stage.addActor(table);
        table.pad(50);
        table.padTop(100);

        //button and text box setup
        String dialogue = "You turn around from the market stall to the sound of your name at a shout. It's your long-time friend and " +
                " fellow bounty hunter, Wesdru. There's an urgency to her mannerisms that raises your heart rate immediately, " +
                "your hand flying to your sword pommel at your hip. 'It's Lorena. Dras has her.' Keegin Dras, this lawless town's " +
                "most feared crime boss. 'What,' you intone breathlessly. 'She doesn't stoop to meddle with cowboys!' Wesdru grabs " +
                "your shoulders roughly and makes brutal eye contact. 'I don't know why. But I do know we have to go NOW. You and I " +
                "both know how cruel Dras can be.'



You only have enough time to buy one thing from the market. What do you take?";


        text = new TextArea(dialogue, Heist.skin);
        table.add(text).grow().colspan(2);

        table.row();

        button1 = new TextButton("Modded Grenade", Heist.skin);
        table.add(button1).width(200).expand();

        button2 = new TextButton("Lockpick", Heist.skin);
        table.add(button2).width(100).expand();

        button1.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.hasGrenade = true;
                game.setScreen(new OutsideScreen(game));
                dispose();
            }
        });

        button2.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.hasLockpick = true;
                game.setScreen(new OutsideScreen(game));
                dispose();
            }
        });
    }

    @Override
    public void show() { //called when screen is shown.
        backgroundMusic.play();
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(1, 0, 0, 1);

        game.batch.begin();
        game.batch.draw(backgroundImage, 0, 0);
        game.batch.end();
        
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        game.batch.dispose();
        backgroundImage.dispose();
        backgroundMusic.dispose();
        stage.dispose();

    }
}

OutsideScreen类

public class OutsideScreen implements Screen {

    final Heist game;

    private final Texture backgroundImage;
    private final Music backgroundMusic;

    private TextButton button1;
    private TextButton button2;
    private TextButton button3;
    private TextArea text;

    private Stage stage;
    private Table table;

    private OrthographicCamera camera;

    public OutsideScreen(final Heist game) {
        this.game = game;

        //load images (64x64 pixels)
        backgroundImage = new Texture("state2.png");

        //load sound effects and music
        backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal("Doom City.mp3"));
        backgroundMusic.setLooping(true);

        //create camera and spriteBatch
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);


        //stage setup
        stage = new Stage(new ScreenViewport());
        Gdx.input.setInputProcessor(stage);

        //table setup
        table = new Table();
        table.setFillParent(true);
        stage.addActor(table);
        table.pad(50);
        table.padTop(100);

        //button and text box setup

        String dialogue = "Hello";

        text = new TextArea(dialogue, Heist.skin);
        table.add(text).grow().colspan(3);

        table.row();

        button1 = new TextButton("Storm them", Heist.skin);
        table.add(button1).width(150).expand();

        button2 = new TextButton("Sweet talk them", Heist.skin);
        table.add(button2).width(150).expand();

        button3 = new TextButton("Climb the building", Heist.skin);
        table.add(button3).width(175).expand();

        //STORM THEM
        button1.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.hasGrenade = true;
//                game.setScreen(new NEXTSCREEN(game));
//                dispose();
            }
        });

        //SWEET TALK THEM
        button2.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.hasLockpick = true;
//                game.setScreen(new NEXTSCREEN(game));
//                dispose();
            }
        });

        //CLIMB THE BUILDING
        button3.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.hasLockpick = false;
                game.hasGrenade = false;
            }
        });
    }

    @Override
    public void show() {
        backgroundMusic.play();
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(1, 0, 0, 1);

        game.batch.begin();
        game.batch.draw(backgroundImage, 0, 0);
        game.batch.end();

        stage.draw();
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        backgroundImage.dispose();
        backgroundMusic.dispose();
        stage.dispose();
    }
}

崩溃问题描述

每次点击MarketScreen的按钮切换到下一屏幕后,游戏总会崩溃:有时运行15秒后先丢失背景图,随后彻底崩溃,错误信息以A fatal error has been detected by the Java Runtime Environment: SIGSEGV (0xb) at pc=0x000000010d7fa85c, pid=22079, tid=23555开头,推测是内存泄漏引发的段错误。

最初我将TextButton、Stage等设为游戏全局属性,仅修改文本和布局;后来重构为每个Screen类独立创建自身组件,崩溃速度变慢但问题依然存在。

解决方法

因需要根据游戏进度的布尔值动态适配屏幕内容,我没有提前创建所有屏幕实例,而是将按钮和监听器的创建代码移至show()方法中,并在hide()方法里调用dispose()释放资源,最终问题得以解决,确认根源是内存泄漏。

内容的提问来源于stack exchange,提问作者user34140

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 05:45:57