我知道在Java中进行JNI调用时“跨越边界”是很慢的。
然而,我想知道什么是它使它变慢吗? 底层jvm实现在执行JNI调用时做了什么,导致调用如此缓慢?< / p >
基本上,JVM解释性地为每个JNI调用构造C参数,代码没有经过优化。
这篇论文中列出了更多的细节
如果你对JNI与本机代码的基准测试感兴趣,这个项目有运行基准测试的代码。
首先,值得注意的是,“慢”;我们说的是几十纳秒就能搞定的事情。对于普通的本地方法,2010年我在Windows桌面上测量的调用平均为40纳秒,在Mac桌面上测量的调用平均为11纳秒。除非你正在进行许多调用,否则你不会注意到。
也就是说,调用本机方法可能比调用普通Java方法更慢。原因包括:
一些额外的讨论,可能有日期,可以在2000年Steve Wilson和Jeff Kesselman的“Java(tm)平台性能:策略和战术”中找到,在“9.2:检查JNI成本”章节中。它大约是这个页面的三分之一,在下面@Philip的评论中提供。
2009年IBM developerWorks论文“使用Java本机接口的最佳实践”;提供了一些使用JNI避免性能缺陷的建议。
值得一提的是,并非所有标记为native的Java方法都是“慢”的。其中一些是intrinsic,这使得它们非常快。要检查哪些是内在的,哪些不是,你可以在vmSymbols.hpp处查找do_intrinsic。
native
do_intrinsic
谈到JNI,有两个方向:java调用c++, c++调用java。Java调用c++(或C)通过“native"关键字非常快,大约50个时钟周期。然而,c++调用Java有点慢。我们做了大量的Java/ c++集成,我的经验法则是每次调用1000个时钟周期,所以你可以每秒进行2M次调用。我无法回答你“为什么很慢”的实际问题,但我大胆猜测,必须做大量工作,使用可变参数将参数从原生c++堆栈转移到Java堆栈,验证所需的任何一致性,反之亦然。
但是,还要记住,一旦从c++调用Java方法,如果该方法返回复杂的数据结构,则还需要为对结果的所有访问进行JNI调用。这同样适用于将复杂的c++结构转换为Java。例如,我们在实践中发现,序列化c++ std::map<string,string>转换为JSON,通过JNI传递字符串,并让Java将其反序列化为Map< string, string >假设您希望将整个映射转换为Java。