在本地代码中处理信号 – 在terminal中使用SIGSEGV导致JVM崩溃

这是我的第一篇文章,所以请大家理解一下。 我有一些Java代码,我有一些本机代码。

Java的一部分目前不是那么有趣,所以我会跳到c ++部分:

//some more trivial includes #include <signal.h> //these are global variables jclass GLOBAL_CLASS; JNIEnv * GLOBAL_ENV; jobject GLOBAL_OBJECT; jmethodID METHOD_ID; void sigproc(int signo) { if (signo == SIGINT) { signal(SIGINT, sigproc); //if Ctrl-c is pressed I want to call a method within my java class //since I can pass only int to this function //I've decided to use global variables GLOBAL_ENV->CallVoidMethod(GLOBAL_OBJECT, METHOD_ID); exit(0); } } JNIEXPORT void JNICALL Java_intern_Work_readFromFile (JNIEnv *env, jobject obj, jobjectArray arr) { /*define a signal trap! */ signal(SIGINT, sigproc); //sigproc(SIGINT); /*initialize the global variables */ GLOBAL_ENV = env; GLOBAL_OBJECT = obj; GLOBAL_CLASS = env->GetObjectClass(obj); //method id is the same so it's better to cache it //at the beginning jmethodID mid = env->GetMethodID(GLOBAL_CLASS, "nativeListener", "(Ljava/lang/String;)V"); METHOD_ID = GLOBAL_ENV->GetMethodID(GLOBAL_CLASS, "closeEverything", "()V"); //let's say I have a while(true) block just below //and some more work is done. } 

这个函数在我的MainClass的开始处被触发。 如果我删除程序正确运行

 GLOBAL_ENV->CallVoidMethod(GLOBAL_OBJECT, METHOD_ID); 

但问题是我需要它,因为我打算释放一些dynamic分配的内存+我需要调用我的类的这个function。 (换句话说,当我在terminal按ctrl-c它说JVM与SIGSEGV cheshes)

看起来我并没有真正理解从内核传递的信号到底发生了什么。 我的全局variablesGLOBAL_ENV仍然是一个正确的指针,我可以使用?

谁能告诉我一个优雅的方式来解决我的问题? 或者任何指导也欢迎! 任何解释…什么都可以。 提前致谢!

以下是JVM崩溃代码的示例:

 A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f9974cfc021, pid=7099, tid=140297087112960 # # JRE version: 6.0_24-b24 # Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops) # Derivative: IcedTea6 1.11.4 # Distribution: Ubuntu 12.04 LTS, package 6b24-1.11.4-1ubuntu0.12.04.1 # Problematic frame: # V [libjvm.so+0x617021] methodOopDesc::result_type() const+0x31 

你的问题是, SIGINT是一个异步信号 ; 它可以发生在任何两个机器指令之间,除非被阻塞

这意味着从信号处理程序调用除了异步安全的函数之外的任何东西都是不安全的(并且,如果您希望是可移植的,则除了设置sig_atomic_t变量外,您不应该做任何事情)。 JVM当然不算是异步安全的。 最有可能的是,你正在中断一些重要的代码中间的JVM,你的方法调用正在破坏JVM状态。

通常用于处理SIGINT是在某处检查一个标志变量( sig_atomic_t类型)。 当你得到一个SIGINT ,设置标志并返回。 循环将以安全,同步的方式来执行处理程序的其余部分。

在你的情况下,你可以产生一个Java线程周期性地调用checkForInterrupt函数来检查前面提到的标志变量。 checkForInterrupt返回当前标志状态,然后你的线程可以选择对其执行操作。

另一个选择是使用pausesigwaitsigsuspend等函数挂起一个线程,直到收到一个信号。 线程然后醒来并同步处理信号。

看看http://javajiggle.com/2008/01/06/if-jni-based-application-is-crashing-check-signal-handling/看来这可能是你所描述的问题&#x3002;

编辑:该链接是旧的,这是它的信息:

http://docs.oracle.com/javase/7/docs/technotes/guides/vm/signal-chaining.html

要使用libjsig.so,请将其与创建/嵌入HotSpot VM的应用程序链接,例如:

cc -L -ljsig -ljvm java_application.c

或者使用LD_PRELOAD环境变量,例如:

导出LD_PRELOAD = / libjsig.so; java_application(ksh)

setenv LD_PRELOAD /libjsig.so; java_application(csh)

插入的signal()/ sigset()/ sigaction()返回保存的信号处理程序,而不是由操作系统看到的Java HotSpot VM安装的信号处理程序。

引入了信号链设施来解决请求增强号4381843。