致命信号11(SIGSEGV)

时间:2013-01-10 17:46:06

标签: android android-ndk java-native-interface

我有一个奇怪的错误,我无法找到它的来源。 logcat中唯一出现的是:

01-10 17:07:10.665: A/libc(20449): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

当我运行我的应用程序时,我没有立即收到此错误,我会在一段随机时间(1分钟到5分钟之间)之后得到它。我无法重现此错误,它似乎是随机的,因为没有其他信息,它很难调试。我试图在我的库中添加一些日志信息,但我仍然不能说出崩溃的位置。

我运行了相同的应用程序x次,我得到了不同的SIGSEGV地址(有时它与以前的地址相同:

01-10 17:29:04.650: A/libc(21588): Fatal signal 11 (SIGSEGV) at 0x6c707063 (code=1)

01-10 17:25:55.165: A/libc(21473): Fatal signal 11 (SIGSEGV) at 0x0069004c (code=1)

01-10 17:11:58.780: A/libc(20742): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

01-10 17:00:02.010: A/libc(20160): Fatal signal 11 (SIGSEGV) at 0x00000018 (code=1)

我的应用程序使用的c ++库具有从服务器接收更新的NetworkThread。在Java端有一个WorkerThread,检查是否有来自NetworkThread的新更新,如果有新的更新,它会通知所有听众。我还有一个LocationSpotter(在Java端),在位置更新时进行一些JNI调用。

有没有办法调试这个或使用我从SIGSEGV获得的地址来调试应用程序?我还使用共享JavaVM对象来获取某些方法来检索当前的JNIEnv(并调用AttachCurrentThread)。这个线程安全吗?

我注意到在收到SIGSEGV错误后(在应用程序实际崩溃之前)我仍然收到来自NetworkThread的更新。这意味着NetworkThread可能正在运行。

我还注意到一行可能是我的问题的根源(在notifyAll方法中),因为在SIGSEGV之前打印的最后一条消息是" notifyAll1" :

for (unsigned i = 0; i < listeners.size(); i++) {
    try {
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll1");
        if (listeners.at(i) == NULL)
            __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");


        listeners.at(i)->update(u); // <- This line is a potential suspect
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");

logcat:

01-10 17:07:10.665: I/FROM C++(20449): notifyAll1
01-10 17:07:10.665: A/libc(20449): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

然后我尝试在每个监听器update方法的第一行打印一个日志,但是没有打印出来(我觉得这很奇怪)。

非常感谢任何帮助

3 个答案:

答案 0 :(得分:3)

大多数时候当您尝试访问当时未创建的任何对象时,会发生致命信号错误。所以要正确检查它们。

答案 1 :(得分:1)

我相信您应该像这样重写 notifyAll 循环:

for (unsigned i = 0; i < listeners.size(); i++) {
  try {
    __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll1 i=%u", i);
    auto listener = *listeners.at(i);

    if (&listener == NULL) {
      __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");
    }
    else {
      __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2 : listener[%u] at %p", i, &listener);
      listener.update(u);
    }
  • 在原始代码中,支票只打印到日志,但更新()仍然会失败(@Robin注意到这一点)
  • 在您的原始代码中,侦听器可能会在check和 update()
  • 之间失效NULL
  • 即使在上述更改之后,如果 listeners.at(i)指向的侦听器对象变为无效, update()也可能会崩溃。

但是由于异常处理,崩溃可能会发生。你没有透露 catch(...)代码,所以我不能谈论这个。

答案 2 :(得分:0)

似乎很明显

if (listeners.at(i) == NULL)
            __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");


        listeners.at(i)->update(u); // <- This line is a potential suspect
        __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");

应该是

if (listeners.at(i) == NULL) {
    __android_log_print(ANDROID_LOG_INFO, "FROM C++", "LISTENER NULL");
} else {
    listeners.at(i)->update(u); // <- This line is a potential suspect
    __android_log_print(ANDROID_LOG_INFO, "FROM C++", "notifyAll2");
}