有什么我们不应该从 JNI 调用中做的事情吗?这些是什么?
例如,我需要使用一个 C++ 库,它在后台执行阻塞和非阻塞 I/O 调用。
在这些情况下,我应该注意什么?我也知道脚本提供了相同的功能(虽然不确定实际的脚本语言)。那会是更好的选择吗(从 调用脚本Java
)?如果是,为什么?
2 回答
JNI 不限制您可以通过多种方式执行的操作,除非您使用GetPrimitiveArrayCritical
andGetStringCritical
:
调用后
GetPrimitiveArrayCritical
,本机代码在调用之前不应运行很长时间ReleasePrimitiveArrayCritical
。我们必须将这对函数中的代码视为在“临界区”中运行。在临界区内,本机代码不得调用其他 JNI 函数,或任何可能导致当前线程阻塞并等待另一个 Java 线程的系统调用。(例如,当前线程不得在另一个 Java 线程正在写入的流上调用 read。)
否则你几乎可以自由地做任何你想做的事情,禁止改变 JVM 和操作系统交互方式的事情(比如替换 JVM 信号处理程序)。
您还询问是否应该运行脚本而不是直接调用本机函数。如果您不知道 C++ 库究竟会做什么,那么执行外部进程会更安全,但它也不太方便(您需要建立一种通信方式)并且可能比在同一进程中进行调用要慢。
从我个人的经验来看,一个坏主意是使用比平常更大的 3rd-party 库作为黑匣子,不知道里面到底发生了什么。线程、I/O、硬件 API 访问、长时间运行的 JNI 调用,以及最糟糕的是自定义内存管理(而不是标准的 lib malloc/free)。可能会出现毛茸茸的问题,包括 JVM 在奇怪的地方报告内存泄漏和异常,和/或莫名其妙的崩溃。有了这样一个库(巨大的 OpenGL 引擎),我们不得不剖析并采用外部流程方法。它通过命名管道进行通信,速度惊人。吸取的教训:总是知道本地库在幕后做什么,这对于 JAR 来说不是那么必要。