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
相关产品推荐
相关产品推荐

