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

Bullet3多线程模式内存错误:示例与排查求助

Bullet多线程初始化阶段内存错误分析求助

测试Bullet多线程功能时,在btCollisionDispatcherMt初始化阶段触发未知地址内存访问错误,已确认btCollisionConfiguration初始化正常,求问题分析及解决办法。

示例代码

#include <btBulletDynamicsCommon.h>
#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h"
#include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h"
#include "BulletCollision/CollisionShapes/btBoxShape.h"
#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h"

int main() {
    btDbvtBroadphase* broadphase = new btDbvtBroadphase();
    btSequentialImpulseConstraintSolverMt* solver = new btSequentialImpulseConstraintSolverMt();
    btDefaultCollisionConstructionInfo cci;

    cci.m_defaultMaxPersistentManifoldPoolSize = 10;
    cci.m_defaultMaxCollisionAlgorithmPoolSize = 10;
    btCollisionConfiguration* collisionConfig = new btDefaultCollisionConfiguration(cci);
    btCollisionDispatcher* dispatcher = new btCollisionDispatcherMt(collisionConfig);
    btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfig);
    dynamicsWorld->setGravity(btVector3(0, -10, 0));

    btBoxShape* boxShape = new btBoxShape(btVector3(1, 1, 1));
    btScalar mass = 1.0;
    btVector3 localInertia(0, 0, 0);
    boxShape->calculateLocalInertia(mass, localInertia);
    btTransform startTransform;
    startTransform.setIdentity();
    startTransform.setOrigin(btVector3(0, 50, 0));
    btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
    btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, boxShape, localInertia);
    btRigidBody* body = new btRigidBody(rbInfo);
    dynamicsWorld->addRigidBody(body);

    for (int i = 0; i < 100; ++i) {
        dynamicsWorld->stepSimulation(1.f / 60.f, 10);
    }

    // Cleanup
    delete body;
    delete motionState;
    delete boxShape;
    delete dynamicsWorld;
    delete solver;
    delete broadphase;
    delete dispatcher;
    delete collisionConfig;

    return 0;
}

CMake配置

cmake_minimum_required(VERSION 3.10)
project(PhysicsSimulation)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
ADD_DEFINITIONS( -DBT_THREADSAFE=1 )

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    add_compile_options(-fsanitize=address)
    add_link_options(-fsanitize=address)
endif()

find_package(Bullet REQUIRED)
message(STATUS "Bullet libraries: ${BULLET_LIBRARIES}")
message(STATUS "Bullet include directories: ${BULLET_INCLUDE_DIRS}")

add_executable(PhysicsSimulation PerformanceTest.cpp)

target_include_directories(PhysicsSimulation PUBLIC ${BULLET_INCLUDE_DIRS})

target_link_libraries(PhysicsSimulation PUBLIC ${BULLET_LIBRARIES})

set_target_properties(PhysicsSimulation PROPERTIES
    DEBUG_POSTFIX "_Debug"
    MINSIZEREL_POSTFIX "_MinsizeRel"
    RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo"
)

错误信息

=================================================================
==10700==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00010473fff4 bp 0x00016b6db190 sp 0x00016b6db120 T0)
==10700==The signal is caused by a READ memory access.
==10700==Hint: address points to the zero page.
    #0 0x10473fff4 in btCollisionDispatcherMt::btCollisionDispatcherMt(btCollisionConfiguration*, int)+0x64 (PhysicsSimulation_Debug:arm64+0x10001bff4)
    #1 0x104727ccc in main PerformanceTest.cpp:54
    #2 0x18bf320dc  (<unknown module>)

==10700==Register values:
 x[0] = 0x0000000000000000   x[1] = 0x0000000000000023   x[2] = 0x0000000000000023   x[3] = 0x0000000108400010  
 x[4] = 0x0000000108400280   x[5] = 0x0000000000000000   x[6] = 0x000000016aee0000   x[7] = 0x0000000000000001  
 x[8] = 0x0000000104770000   x[9] = 0x00000001081039d0  x[10] = 0x0000000000000005  x[11] = 0x00000000ffffffff  
x[12] = 0x0000000000000000  x[13] = 0xda122256f3c39294  x[14] = 0x0000000000007e01  x[15] = 0x0000000000000006  
x[16] = 0x0000000105044a98  x[17] = 0x00000001050840b8  x[18] = 0x0000000000000000  x[19] = 0x0000000108400200  
x[20] = 0x0000000000000028  x[21] = 0x000000016b6db360  x[22] = 0x0000000104b9d910  x[23] = 0x000000016b6db3e0  
x[24] = 0x0000000108405354  x[25] = 0x000000018bfa62db  x[26] = 0x0000000000000000  x[27] = 0x0000000000000000  
x[28] = 0x0000000000000000     fp = 0x000000016b6db190     lr = 0x000000010473fff4     sp = 0x000000016b6db120  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (PhysicsSimulation_Debug:arm64+0x10001bff4) in btCollisionDispatcherMt::btCollisionDispatcherMt(btCollisionConfiguration*, int)+0x64
==10700==ABORTING
zsh: abort      

额外环境信息

  • 设备:搭载M3芯片的Mac
  • Bullet SDK:双精度模式构建
  • 问题触发点:btCollisionDispatcherMt初始化阶段

LLDB调试信息

(lldb) run
Process 12734 launched: '/Users/.../Documents/InternalCode/PlayGround/Bullet/C++/Arena/MT1/build/PhysicsSimulation_Debug' (arm64)
Process 12734 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003458 PhysicsSimulation_Debug`main at PerformanceTest.cpp:53:41
   50       cci.m_defaultMaxPersistentManifoldPoolSize = 10;
   51       cci.m_defaultMaxCollisionAlgorithmPoolSize = 10;
   52       btCollisionConfiguration* collisionConfig = new btDefaultCollisionConfiguration(cci);
-> 53       btCollisionDispatcher* dispatcher = new btCollisionDispatcherMt(collisionConfig);
   54       // btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfig);
   55       // dynamicsWorld->setGravity(btVector3(0, -10, 0));
   56   
Target 0: (PhysicsSimulation_Debug) stopped.
(lldb) frame variable
(btDbvtBroadphase *) broadphase = 0x0000000103503ac0
(btSequentialImpulseConstraintSolverMt *) solver = 0x0000000100203790
(btDefaultCollisionConstructionInfo) cci = {
  m_persistentManifoldPool = nullptr
  m_collisionAlgorithmPool = nullptr
  m_defaultMaxPersistentManifoldPoolSize = 10
  m_defaultMaxCollisionAlgorithmPoolSize = 10
  m_customCollisionAlgorithmMaxElementSize = 0
  m_useEpaPenetrationAlgorithm = 1
}
(btCollisionConfiguration *) collisionConfig = 0x0000000103d03880
(btCollisionDispatcher *) dispatcher = 0x00000000000002c0
(lldb) step
Process 12734 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    frame #0: 0x00000001006613b4 libBulletCollision.3.26.dylib`btCollisionDispatcherMt::btCollisionDispatcherMt(btCollisionConfiguration*, int) + 108
libBulletCollision.3.26.dylib`btCollisionDispatcherMt::btCollisionDispatcherMt:
->  0x1006613b4 <+108>: ldr    x8, [x0]
    0x1006613b8 <+112>: ldr    x8, [x8, #0x18]
    0x1006613bc <+116>: blr    x8
    0x1006613c0 <+120>: mov    x21, x0
Target 0: (PhysicsSimulation_Debug) stopped.
(lldb) frame variable
(lldb) 

问题分析

  1. 从崩溃栈和LLDB调试结果来看,btCollisionDispatcherMt构造函数内部尝试访问空指针(地址0x0),核心原因大概率是Bullet库构建时未正确启用多线程支持,或者应用编译宏与库的构建宏不匹配。
  2. BT_THREADSAFE宏一致性问题:CMake中添加了-DBT_THREADSAFE=1,但如果Bullet库本身是在未定义该宏的情况下构建的,会导致多线程类内部逻辑缺失,访问未初始化的成员变量。
  3. 多线程组件依赖缺失:btCollisionDispatcherMt需要Bullet库在构建时启用多线程相关模块,若库构建时未开启,链接时虽能找到类符号,但内部实现不完整,触发空指针访问。
  4. 双精度配置不匹配:应用与Bullet库必须同时使用双精度(BT_USE_DOUBLE_PRECISION),否则会因类型大小差异导致内存访问错误。

解决建议

  • 重新构建Bullet库:确保构建时定义BT_THREADSAFE=ON,同时开启多线程相关编译选项(如BUILD_MULTITHREADED,不同版本选项名可能有差异),且与应用一致使用双精度。
  • 验证宏定义一致性:确认应用编译时的BT_THREADSAFE、BT_USE_DOUBLE_PRECISION等宏与Bullet库构建时完全一致,避免因宏差异导致类结构不匹配。
  • 替换多线程世界类:将btDiscreteDynamicsWorld改为btDiscreteDynamicsWorldMt,保证多线程组件链路完整。
  • 调整池大小参数:增大cci.m_defaultMaxPersistentManifoldPoolSize和m_defaultMaxCollisionAlgorithmPoolSize的值(当前设为10过小,建议改为默认值或更大数值,比如100)。
  • 检查预编译库兼容性:若使用预编译Bullet库,确认其是启用多线程、双精度的版本,且与当前系统架构(arm64)匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:20:56