Java Native Interface 偷偷摸摸的 fork 行为

标签 java java-native-interface fork

经过非常长时间的搜索和相关错误,我发现了这种奇怪的行为:

如果在 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, NULL, NULL, timeout);

  return;
}

然后我用 strace 运行可执行文件,select 不是用我打印的 PID 执行的,而是用 child 的 PID 执行的,原始对象实际上在等待互斥锁(这如果我在普通的小型 C 程序中执行相同的调用,则不会发生。

strace -f -o strace_output.txt java SelectJNI 打印:

PID: 46811 

然后 grep select\( strace_output.txt 将返回:

46812 select(0, NULL, NULL, NULL, {tv_sec=30, tv_usec=0} <unfinished ...>

我的猜测是 JNI 正在 fork ,以某种方式用它自己的包装版本替换原始选择,可能是为了保持响应。

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

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

最佳答案

JVM 确实可以 fork ,但这样做是为了创建新的 JVM 线程,而不是整个进程。虽然 46811 是 PID,但实际运行您的代码的线程具有 TID 46812(这是 strace 打印的内容),同时仍在 PID 46811 下运行。替换 getpid在示例中使用 gettid 应该会导致一致的输出。

关于Java Native Interface 偷偷摸摸的 fork 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66122018/

相关文章:

java - 如何在java中写出一个二维数组以便C程序可以读取它

java - 游戏小程序未在2D游戏中运行(while循环)

java - 如何在Android中将字符串从java代码发送到 native C

java - JNI 运行进程而不是使用库

licensing - 如何进行 fork ,进行重大更改并给予应有的信誉?

c - 套接字通信的奇怪循环

java - 如何自动删除Java类中的私有(private)字段和方法

java - TestNG + Mockito,如何测试抛出的异常和模拟调用

java - 加载 JNI 库时出现 Unsatisfied Link 错误

c - 在下面的代码中 fork 后发送信号有什么问题