Native Crash 排查
场景
线上出现 SIGSEGV (signal 11) 崩溃,堆栈全是 native 地址,无法直接定位代码行。
排查与方案
1. 获取崩溃信息
从 Crashlytics / Bugly / Tombstone 获取:
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
backtrace:
#00 pc 0001a3f4 /data/app/com.example/lib/arm64/libnative.so
#01 pc 0001b210 /data/app/com.example/lib/arm64/libnative.so
#02 pc 00089abc /system/lib64/libc.so (pthread_create+...)
2. 符号化还原
# 使用 NDK 的 addr2line 将地址还原为函数名 + 行号
# 需要编译时保留了 debug symbols 的 so(不是 strip 后的)
$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-addr2line \
-e app/build/intermediates/merged_native_libs/release/out/lib/arm64-v8a/libnative.so \
-f 0x1a3f4 0x1b210
# 或使用 ndk-stack 直接解析 tombstone
adb logcat | ndk-stack -sym app/build/intermediates/.../arm64-v8a/
3. 常见 Native Crash 类型
| 信号 | 含义 | 常见原因 |
|---|---|---|
| SIGSEGV (11) | 非法内存访问 | 空指针、野指针、数组越界 |
| SIGABRT (6) | 主动 abort | assert 失败、JNI 异常未清 |
| SIGBUS (7) | 内存对齐错误 | 非对齐访问、映射文件损坏 |
| SIGFPE (8) | 算术异常 | 除零 |
4. JNI 常见崩溃
// ❌ 常见错误1:JNI 异常未检查
jstring str = (*env)->CallObjectMethod(env, obj, methodId);
// 如果 Java 层抛了异常,str 为 NULL
const char *cStr = (*env)->GetStringUTFChars(env, str, NULL); // CRASH
// ✅ 修复:检查异常
jstring str = (*env)->CallObjectMethod(env, obj, methodId);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env);
return; // 安全退出
}
预防措施
- 编译时开启
-fsanitize=address(ASan)检测内存错误 - CI 中运行 Native 单元测试
- 关键 JNI 调用添加 NULL check
面试答题要点
- 用
addr2line/ndk-stack符号化还原堆栈 - 分辨不同 Signal 类型及其常见原因
- JNI 层要主动检查异常和空指针
- 提到 ASan 和 Breakpad 工具