微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java Native Interface 偷偷摸摸的分叉行为

如何解决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 正在分叉,并且以某种方式用它自己的包装版本替换原始选择,可能会保持响应。

我有很多的问题,但我更关心的是:

  1. 我的假设正确吗? JNI 取代了我脚下的函数
  2. 此行为是否记录在某处?
  3. 调用实际选择的过程似乎总是第一个孩子的过程。我可以依靠吗?如果没有,我如何找出 select 实际运行的位置?

解决方法

JVM 可能确实会分叉,但它这样做是为了创建新的 JVM 线程,而不是整个进程。虽然 46811 是 PID,但实际运行相关代码的线程的 TID 为 46812(这是 strace 打印的内容),同时仍在 PID 46811 下运行。将 getpid 替换为 {{示例中的 1}} 应该导致一致的输出。

,

我想详细说明@nanofarad 接受的答案,并明确解决我自己问题的 3 点。

我的猜测是 JNI 正在分叉,并以某种方式取代了 原始选择带有自己的包装版本,可能会保留 反应灵敏。 [...]

  1. 我的假设正确吗? JNI 取代了我脚下的函数?

不,不是。

JNI 执行的 select 没有什么特别之处。

JNI 将其替换为“分叉进程的东西”的假设是错误的:我只是误解了 strace 为 PID 打印的 TID。

JNI 只是在 Java 线程中执行 strace。

  1. 此行为是否记录在某处?

不需要:因为 JNI 调用是在调用 Java 线程中执行的,所以没有什么可写的。

  1. 调用实际选择的过程似乎总是第一个孩子的过程(等等...)

它是第一个生成的线程的 TID,它似乎总是等于 PID + 1,但我是一个可能的行为(Java 线程是在运行时启动后立即创建的),它不一定是。

>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。