LibGDX销毁Box2D刚体触发Fatal signal 11(SIGSEGV)错误求助
Box2D销毁刚体后崩溃(SIGSEGV)的解决方案
错误信息
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x71929823b800 in tid 13461 (GLThread 46), pid 13432 (com.mygdx.game) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A Cmdline: com.mygdx.game 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A pid: 13432, tid: 13461, name: GLThread 46 >>> com.mygdx.game <<< 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #00 pc 0000000000036958 /data/app/~~Kbde8VLpHehJDoH_wtbk9g==/com.mygdx.game-a7HrSt4SXhSXonRVircwDQ==/lib/x86_64/libgdx-box2d.so (b2BlockAllocator::Allocate(int)+72) (BuildId: 718b99a1c37cd23164f86ef804f0169668c31984) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #01 pc 000000000001b04d /data/app/~~Kbde8VLpHehJDoH_wtbk9g==/com.mygdx.game-a7HrSt4SXhSXonRVircwDQ==/lib/x86_64/libgdx-box2d.so (b2World::CreateBody(b2BodyDef const*)+29) (BuildId: 718b99a1c37cd23164f86ef804f0169668c31984) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #02 pc 0000000000037580 /data/app/~~Kbde8VLpHehJDoH_wtbk9g==/com.mygdx.game-a7HrSt4SXhSXonRVircwDQ==/lib/x86_64/libgdx-box2d.so (Java_com_badlogic_gdx_physics_box2d_World_jniCreateBody+160) (BuildId: 718b99a1c37cd23164f86ef804f0169668c31984) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #05 pc 000000000016ad5c /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.badlogic.gdx.physics.box2d.World.createBody+128) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #07 pc 000000000024981a /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Gunstuff.Stuff.Bullet.createCircleBody+46) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #09 pc 00000000002498fa /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Gunstuff.Stuff.Bullet.<init>+102) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #11 pc 0000000000249418 /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Gunstuff.Guns.Ak.shoot+144) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #13 pc 000000000024951c /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Gunstuff.Guns.Ak.update+200) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #15 pc 000000000024a1e4 /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Screens.GameScreen.gameUpdate+76) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #17 pc 000000000024a6ee /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.mygdx.game.Screens.GameScreen.render+50) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #19 pc 00000000000bf6f0 /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.badlogic.gdx.Game.render+20) 2023-06-01 14:38:19.069 13486-13486 DEBUG pid-13486 A #21 pc 00000000000df452 /data/data/com.mygdx.game/code_cache/.overlay/base.apk/classes.dex (com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame+454)
问题根源
- 迭代器逻辑错误:
sweepDeadBodies方法跳过了第一个Body,导致大量待销毁刚体堆积,破坏Box2D内存分配器状态。 - 异步销毁风险:使用
Gdx.app.postRunnable异步执行销毁操作,Box2D不允许跨线程或异步修改世界状态,会引发内存访问冲突。 - 未清理关联对象:销毁Body后未从
bullets数组移除对应Bullet,后续渲染/更新可能访问已释放内存。
修复步骤
1. 修正sweepDeadBodies方法
修复迭代逻辑,同时清理关联的Bullet对象:
private void sweepDeadBodies() { world.getBodies(bodiesToDestroy); Iterator<Body> iterator = bodiesToDestroy.iterator(); while (iterator.hasNext()) { Body body = iterator.next(); String data = (String) body.getUserData(); if (data != null && data.equals("delete")) { // 从bullets数组移除对应Bullet for (int j = bullets.size - 1; j >= 0; j--) { Bullet bullet = bullets.get(j); if (bullet.body == body) { bullets.removeIndex(j); break; } } world.destroyBody(body); body.setUserData(null); // 避免重复处理 } } bodiesToDestroy.clear(); // 清空数组释放内存 }
2. 调整销毁时机,移除异步调用
Box2D要求所有世界操作(创建/销毁Body)必须在同一个线程执行,且不能在world.step过程中进行。修改render方法,将销毁操作放在world.step之后:
@Override public void render(float delta) { // 先执行Box2D步进 world.step(1 / 45f, 6, 2); // 步进完成后立即销毁待处理刚体 sweepDeadBodies(); Gdx.gl.glClearColor(1,0,1,1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); gameUpdate(delta); // 后续渲染逻辑保持不变 main.shapeRenderer.setProjectionMatrix(main.camera.combined); main.camera.position.set(player.body.getPosition().x * PPM, player.body.getPosition().y * PPM, 0); main.camera.update(); mapRenderer.setView(main.camera); mapRenderer.render(); b2dr.render(world, new Matrix4(main.camera.combined).scl(PPM)); Main.batch.setProjectionMatrix(main.camera.combined); Main.batch.begin(); gameRender(Main.batch); Main.batch.end(); Main.stage.act(delta); Main.stage.draw(); main.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); main.shapeRenderer.setColor(Color.GRAY); for (int i = 0; i < bullets.size; i++) { main.shapeRenderer.circle(bullets.get(i).position.x, bullets.get(i).position.y, bullets.get(i).size); } main.shapeRenderer.end(); }
3. 移除gameUpdate中的异步代码
删除gameUpdate里的Gdx.app.postRunnable调用:
public void gameUpdate(float delta) { // 移除这段异步销毁代码 // Gdx.app.postRunnable(new Runnable() { // @Override // public void run() { // sweepDeadBodies(); // } // }); player.update(); player.setDirection(joystickL.direction); player.gun.update(joystickR); for (int i = 0; i < enemies.size; i++) { enemies.get(i).update(); enemies.get(i).handgun.update(joystickR); } for (int i = 0; i < bullets.size; i++) { bullets.get(i).update(); } if (player.gun.isFire && player.gun.ammo > 0) { if (Rumble.getRumbleTimeLeft() > 0) { Rumble.tick(delta); main.camera.translate(Rumble.getPos()); } } }
4. 清理ContactListener冗余代码
ContactListener中定义的bodiesToDestroy数组未被使用,直接删除:
// 移除这行冗余代码 // public Array<Body> bodiesToDestroy = new Array<Body>(); @Override public void beginContact(Contact contact) { Fixture fa = contact.getFixtureA(); Fixture fb = contact.getFixtureB(); if(fa == null || fb == null) System.out.println("no fixture"); if(fa.getBody() == null || fb.getBody() == null) System.out.println("no body"); hit_wall_bullet(fa, fb); } // 其他方法保持不变
额外建议
- Bullet初始化时,将Body的UserData设置为
"bullet"而非空值,避免误判销毁条件。 - 严格遵守Box2D规则:碰撞回调中禁止直接修改世界状态(如销毁Body),必须标记后统一处理。
内容的提问来源于stack exchange,提问作者ognevo
相关产品推荐
相关产品推荐

