如何解决Java Native Interface 偷偷摸摸的分叉行为
如果在 Linux 上我运行单个 JNI 方法来执行 select
:
JNIEXPORT void JNICALL Java_SelectJNI_select(jnienv *env,jobject thisObj) {
// Print the curerent PID
fprintf(stderr,"PID: %d\n",getpid());
// Wait for 30 seconds
struct timeval *timeout = (struct timeval *) calloc(1,sizeof(struct timeval));
timeout->tv_sec = 30;
timeout->tv_usec = 0;
select(0,NULL,timeout);
return;
}
然后我用 strace 运行可执行文件,select
不是用我打印的 PID 执行的,而是用孩子的 PID 执行的,原始对象实际上在等待互斥锁(这不是如果我在一个普通的小型 C 程序中执行相同的调用,就会发生这种情况)。
说 strace -f -o strace_output.txt java SelectJNI
打印:
PID: 46811
然后 grep select\( strace_output.txt
将返回:
46812 select(0,{tv_sec=30,tv_usec=0} <unfinished ...>
我的猜测是 JNI 正在分叉,并且以某种方式用它自己的包装版本替换原始选择,可能会保持响应。
我有很多的问题,但我更关心的是:
解决方法
JVM 可能确实会分叉,但它这样做是为了创建新的 JVM 线程,而不是整个进程。虽然 46811 是 PID,但实际运行相关代码的线程的 TID 为 46812(这是 strace 打印的内容),同时仍在 PID 46811 下运行。将 getpid
替换为 {{示例中的 1}} 应该导致一致的输出。
我想详细说明@nanofarad 接受的答案,并明确解决我自己问题的 3 点。
我的猜测是 JNI 正在分叉,并以某种方式取代了 原始选择带有自己的包装版本,可能会保留 反应灵敏。 [...]
- 我的假设正确吗? JNI 取代了我脚下的函数?
不,不是。
JNI 执行的 select
没有什么特别之处。
JNI 将其替换为“分叉进程的东西”的假设是错误的:我只是误解了 strace
为 PID 打印的 TID。
JNI 只是在 Java 线程中执行 strace。
- 此行为是否记录在某处?
不需要:因为 JNI 调用是在调用 Java 线程中执行的,所以没有什么可写的。
- 调用实际选择的过程似乎总是第一个孩子的过程(等等...)
它是第一个生成的线程的 TID,它似乎总是等于 PID + 1,但我是一个可能的行为(Java 线程是在运行时启动后立即创建的),它不一定是。
>版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。