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

