跳到主要内容

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)主动 abortassert 失败、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

面试答题要点

  1. addr2line / ndk-stack 符号化还原堆栈
  2. 分辨不同 Signal 类型及其常见原因
  3. JNI 层要主动检查异常和空指针
  4. 提到 ASan 和 Breakpad 工具

相关链接