从C++类方法返回KMM创建的NSObject触发EXC_BAD_ACCESS的原因及解决方法
C++返回KMM创建的NSObject触发EXC_BAD_ACCESS异常的原因与解决方法
在从C++类方法返回由Kotlin Multiplatform(KMM)创建的NSObject时,触发了EXC_BAD_ACCESS异常(由Sentry错误追踪系统上报),以下是对问题原因的分析及预防方案:
问题原因
- 内存管理逻辑冲突:KMM生成的NSObject默认采用ARC(自动引用计数)管理内存,但你的C代码手动调用了
retain和release,这会和ARC的自动计数逻辑冲突。当ARC自动释放SMLMountPoint实例后,C类里的m_mountPoint就变成了野指针,调用getMountPoint访问时直接触发崩溃。 - 对象生命周期不匹配:在实例化逻辑中,旧的
MountPoint被调用deleteLater()后,其析构函数会执行[m_mountPoint release],但如果此时SMLMountPoint已经被ARC释放,就会导致重复释放或访问已回收的内存。另外,用alloc创建的point变量,其内存管理和C++的手动操作叠加,进一步加剧了生命周期混乱。 - 野指针直接访问:崩溃发生在
getMountPoint返回m_mountPoint的位置,说明此时m_mountPoint指向的内存已经被释放,变成无效指针,访问0x10这个无效地址触发了SEGV_NOOP错误。
预防与解决方法
统一内存管理策略:删掉C++代码里的手动
retain/release,交给ARC全权处理SMLMountPoint的内存。修改后的代码如下:AgraQML::MountPoint::MountPoint(SMLMountPoint* point) { m_mountPoint = point; // 移除[point retain],ARC自动管理引用 } AgraQML::MountPoint::~MountPoint() { // 移除[m_mountPoint release],ARC自动释放对象 }注意:要保证
SMLMountPoint实例在MountPoint对象的生命周期内不会被ARC提前释放,必要时可以在Objective-C代码中用__strong修饰符延长其生命周期。修正实例化逻辑的内存操作:用
alloc创建SMLMountPoint后,ARC会自动处理其引用计数,不需要手动release。当旧的MountPoint被deleteLater()时,因为已经移除了手动release操作,不会再和ARC的释放逻辑冲突。添加空值检查避免野指针:在
getMountPoint方法里先判断m_mountPoint是否为nil,避免返回无效指针:SMLMountPoint* AgraQML::MountPoint::getMountPoint() const { return m_mountPoint ? m_mountPoint : nullptr; }同时,在调用
getMountPoint返回的对象之前,也要先做空值判断,再执行后续操作。用Objective-C++特性封装对象:可以在C++类中用
__strong修饰m_mountPoint,让ARC自动管理其引用,确保内存操作一致:// 在MountPoint类中定义成员变量 __strong SMLMountPoint* m_mountPoint; // 构造函数无需手动retain AgraQML::MountPoint::MountPoint(SMLMountPoint* point) : m_mountPoint(point) {} // 析构函数无需手动release AgraQML::MountPoint::~MountPoint() {}
相关原代码片段
C++ MountPoint类原代码
AgraQML::MountPoint::MountPoint(SMLMountPoint* point) { [point retain]; m_mountPoint = point; } AgraQML::MountPoint::~MountPoint() { [m_mountPoint release]; } SMLMountPoint* AgraQML::MountPoint::getMountPoint() const { return m_mountPoint; }
实例化逻辑原代码
SMLMountPoint *point = [[SMLMountPoint alloc] initWithRecord:mountPointRecord.toNSString()]; auto oldMountPoint = findChild<AgraQML::MountPoint*>(); AgraQML::MountPoint* mountPoint; if (oldMountPoint == nullptr || oldMountPoint->path() != QString::fromNSString(point.path)) { // 创建新的MountPoint mountPoint = new AgraQML::MountPoint(point); mountPoint->setParent(this); if (oldMountPoint != nullptr) // 移除旧的MountPoint oldMountPoint->deleteLater(); } else { // 使用旧的MountPoint mountPoint = oldMountPoint; }
异常信息
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: SEGV_NOOP at 0x0000000000000010 Crashed Thread: 0 Application Specific Information: __cxa_guard_release > _setInvalidatesViewsOnAppearanceChange: > application:didFinishLaunchingWithOptions: > KERN_INVALID_ADDRESS at 0x10. Thread 0 Crashed: 0 AgraGPS 0x2009acb74 AgraQML::MountPoint::getMountPoint (MountPoint.mm:16) 1 AgraGPS 0x20099877c AgraQML::NTRIP::restoreGetData (NTRIP.mm:61)
内容的提问来源于stack exchange,提问作者cj-
相关产品推荐
相关产品推荐

