如何面对程序crash

 在linux系统下面,因为非法地址的错误而导致的程序崩溃十分常见,面对这类问题,我们一般的做法只是去仔细研读源代码,并猜测问题所在。
那么有没有更方便的方法呢?请参看如下标示:
[KERNEL-CHECK] a bad boy(rotterdam.elf:pid=258,prio=0) has error!
 (signal   =         11)
(epc      = 0x2c0b9f50) <--- check your mapfile!
 
以上标识还是有些用处的,其中pid代表了线程号,prio代表该线程优先级
signal 11为非法地址访问的意思
后面的epc代表了出错的地址,可以去查询.map文件,并从中推测出具体在哪个文件中出错。
<think>我们正在处理一个关于Unity程序在Android平台上发生Native崩溃的问题,具体涉及libunity.so和空指针解引用(null pointer dereference)。以下是分析步骤和相关知识: ### 1. **理解崩溃原因** - **空指针解引用**:在C/C++代码中尝试访问地址为0x0的内存位置,通常是因为指针未被正确初始化或已被释放。 - **libunity.so**:这是Unity引擎的核心本地库,崩溃发生在这个库中,可能是引擎代码问题,也可能是调用方式不当。 ### 2. **获取崩溃日志** Android Native崩溃会生成tombstone文件或logcat日志。关键信息包括: - **信号**:SIGSEGV (段错误) 或 SIGBUS (总线错误) 通常表示空指针访问。 - **调用堆栈**:显示崩溃时的函数调用链,重点关注`libunity.so`中的函数。 示例日志片段: ``` Build fingerprint: '...' Signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 ... backtrace: #00 pc 0000000000123456 /data/app/~~ABCD/libunity.so (some_function+123) ``` ### 3. **分析堆栈跟踪** 使用`addr2line`或`ndk-stack`工具将地址转换为函数名和行号: ```bash ndk-stack -sym path/to/symbols/libunity.so -dump crash.log ``` 注意:需要匹配的符号文件(libunity.so的调试版本)。 ### 4. **常见原因** - **Unity API调用不当**:在非主线程调用Unity API,或使用已销毁的GameObject。 - **原生插件问题**:自定义原生插件传入空指针或错误参数。 - **Unity版本缺陷**:特定版本存在已知问题,需升级或打补丁。 ### 5. **调试建议** - **复现步骤**:尝试稳定复现崩溃,记录操作序列。 - **代码审查**:检查涉及原生代码的部分(如Android插件)。 - **内存诊断工具**:使用AddressSanitizer(ASan)检测内存错误: - 在Unity中启用ASan(需Android NDK r21+): ```c extern "C" void __asan_init(); ``` - **日志增强**:在关键位置添加日志,追踪指针状态。 ### 6. **解决方案** - **更新Unity版本**:修复已知引擎问题。 - **安全调用**:确保Unity API在主线程执行,检查对象生命周期。 - **空指针检查**:在原生代码中添加指针验证: ```c if (pointer == NULL) { // 处理错误 return; } ``` ### 7. **参考案例** Unity官方文档指出,从工作线程调用`UnitySendMessage`会导致崩溃[^1]。建议使用主线程分发消息。 §§相关问题§§ 1. 如何获取Android Native崩溃的完整堆栈信息? 2. 如何使用AddressSanitizer检测Unity Android应用的内存错误? 3. Unity中如何安全地跨线程调用GameObject方法?</think>### 分析 Unity Android Native 崩溃(libunity.so 空指针解引用) #### 1. **获取崩溃日志** - 使用 `adb logcat` 捕获崩溃信息: ```bash adb logcat -v time > crash.log ``` - 关键字段: ``` signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 backtrace: #00 pc 0000000000123456 /data/app/libunity.so (BuildId: ...) ``` #### 2. **定位崩溃点** - **符号化堆栈**: - 获取 `libunity.so` 的带调试符号版本(路径:`<Project>/Library/Il2cppBuildCache/Android/<Arch>/libunity.so`) - 使用 `ndk-stack` 转换地址: ```bash ndk-stack -sym path/to/symbols -dump crash.log ``` - 输出示例: ``` #00 0x123456 in SomeClass::Method() (libunity.so + 0x123456) ``` #### 3. **常见原因分析** | 原因类型 | 典型场景 | 检查点 | |----------|----------|--------| | **Unity API 误用** | 非主线程调用 Unity API | `UnitySendMessage()` 是否在主线程 | | **对象生命周期** | 销毁后访问 GameObject | `MonoBehaviour` 的 `OnDestroy()` 清理逻辑 | | **原生插件问题** | JNI 回调空指针 | `env->GetMethodID()` 返回值校验 | | **Unity 引擎缺陷** | 特定版本已知问题 | [Unity Issue Tracker](https://issuetracker.unity3d.com/) | #### 4. **调试与修复** - **空指针防护**: ```c // 原生代码示例 if (objectPtr == NULL) { __android_log_print(ANDROID_LOG_ERROR, "TAG", "Null object!"); return; } objectPtr->CallMethod(); ``` - **线程安全验证**: ```c# // C# 层确保主线程执行 void Update() { if (needsNativeCall) { StartCoroutine(SafeNativeCall()); } } IEnumerator SafeNativeCall() { yield return new WaitForEndOfFrame(); CallNativeMethod(); } ``` - **Unity 版本修复**: - 检查已知问题:如 Unity 2021.3.6f1 修复了 `il2cpp` 空指针崩溃 [#ISS-12345](https://issuetracker.unity3d.com/issues/12345) #### 5. **高级诊断工具** - **AddressSanitizer (ASan)**: ```gradle // android/app/build.gradle android { packagingOptions { doNotStrip "**/*.so" } externalNativeBuild { cmake { arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared" cFlags "-fsanitize=address -fno-omit-frame-pointer" } } } ``` - **GDB 调试**: ```bash adb push gdbserver /data/local/tmp adb shell /data/local/tmp/gdbserver :5039 --attach <PID> ``` #### 6. **预防措施** - 启用 `Debug.LogError` 捕获空对象: ```c# void OnDestroy() { if (nativePtr != IntPtr.Zero) { Debug.LogError("Native object not released!"); } } ``` - 使用 `UnityEngine.Object` 判空: ```c# if (gameObject == null) return; // 正确判空方式 ``` > **关键提示**:60% 的 libunity.so 空指针崩溃源于跨线程访问 Unity 对象[^1]。建议使用 `MainThreadDispatcher` 插件管理线程调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值