JNA Native.setXXX() 慢

JNA Native.setXXX() slow

不确定这里是否适合提问。我在 YourKit 中注意到(但任何其他分析器都会这样做)Native.setShort 对我的情况做出了巨大贡献。这会在 Structure 中设置字段以填充 jna 库调用参数。 SetShort 被称为 jna lib 代理调用下的大约 10 个级别。对 windows' kernel32.dll 的实际函数调用根本没有出现在采样中。当 return 值时 Structure.read activity 也没有。

现在,我查看了这个和其他原始值设置器的作用:它们获取参数的地址并通过 memcpy 或 bcopy 将 sizeof(argument) 字节移动到目标地址,可能被 try/catch 宏。为什么完成?为什么不只是像这样:

*((short*) target) = value

这会更有效率还是 try/catch 在这里很重要?周围的 PSTART/PEND 宏似乎并不总是生成 try/catch。 这是来自 git.

的最新 JNA grab 4.2.0

更新: 看来这是profiler跟我开的恶作剧。今天,我看到浪费的时间更均匀地分布在进出实际本机调用的其他调用堆栈级别。

我的解决方案是使用 JNA 直接映射:在 OS API 之上的我自己的 DLL 中添加另一个函数,它采用原始指针而不是 Structure.ByReference 到 return 值。使用每个 return 参数的单元素原始数组调用此函数花费 370 ns 与 1500 ns(不包括 new Structure.ByReference())。

所以,最后,Native.setXXX() 方法真的很慢,连同围绕 JNA 方法调用的所有粘合代码。但是 JNA 直接映射可以做到。我从未测试过实际的 JNI 调用,因此无法在此处比较时间。

在 *nix 系统上,PSTART/PEND 执行 setjmp/longjmp 来捕获一系列内存故障(但前提是 Native.setProtected(true) ).在 Windows 上,它使用结构化异常处理(基本上是 try/catch)来做同样的事情,并且默认打开。

即使启用,与 JNI 转换本身的开销(从 Java 到 C 或相反)相比,它们也不太可能增加太多开销。

通常,将 Structure 传递给本机代码并不是非常有效,因为自动写入和读取在很大程度上依赖于反射将 Java 字段复制到本机内存中。不过,在大多数情况下,这并不重要。

对于发现瓶颈的少数情况,您会希望使用 JNA 的直接映射并将自己限制在原始参数上。