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

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)

问题根源

  1. 迭代器逻辑错误:sweepDeadBodies方法跳过了第一个Body,导致大量待销毁刚体堆积,破坏Box2D内存分配器状态。
  2. 异步销毁风险:使用Gdx.app.postRunnable异步执行销毁操作,Box2D不允许跨线程或异步修改世界状态,会引发内存访问冲突。
  3. 未清理关联对象:销毁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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:52:00