Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是什么使得JNI调用缓慢?_Java_Performance_Java Native Interface - Fatal编程技术网

Java 是什么使得JNI调用缓慢?

Java 是什么使得JNI调用缓慢?,java,performance,java-native-interface,Java,Performance,Java Native Interface,我知道在Java中进行JNI调用时“跨越边界”是很慢的 但是我想知道是什么让它变慢的? 底层jvm实现在进行一个JNI调用时做了什么,使它变得如此缓慢?基本上,jvm为每个JNI调用解释性地构造C参数,并且代码没有优化 中还列出了更多细节 如果您对JNI与本机代码的基准测试感兴趣,那么就有运行基准测试的代码。首先,值得注意的是,通过“慢”,我们谈论的是可能需要几十纳秒的时间的东西。对于普通的本机方法,在2010年,我在Windows桌面上测量的调用平均为40纳秒,在Mac桌面上测量的调用平均为1

我知道在Java中进行JNI调用时“跨越边界”是很慢的

但是我想知道是什么让它变慢的?
底层jvm实现在进行一个JNI调用时做了什么,使它变得如此缓慢?

基本上,jvm为每个JNI调用解释性地构造C参数,并且代码没有优化

中还列出了更多细节


如果您对JNI与本机代码的基准测试感兴趣,那么就有运行基准测试的代码。

首先,值得注意的是,通过“慢”,我们谈论的是可能需要几十纳秒的时间的东西。对于普通的本机方法,在2010年,我在Windows桌面上测量的调用平均为40纳秒,在Mac桌面上测量的调用平均为11纳秒。除非你打了很多电话,否则你不会注意到的

也就是说,调用本机方法可能比调用普通Java方法慢。原因包括:

  • JVM不会内联本机方法。它们也不会为这台特定的机器及时编译——它们已经编译好了
  • 可以复制Java数组以在本机代码中进行访问,然后再复制回来。成本可以与阵列的大小成线性关系。我在Windows桌面上测量了100000个阵列的JNI复制,平均约为75微秒,在Mac上为82微秒。幸运的是,可以通过或直接访问
  • 如果该方法被传递了一个对象,或者需要进行回调,那么本机方法很可能会自己调用JVM。从本机代码访问Java字段、方法和类型需要类似于反射的东西。签名以字符串形式指定,并从JVM中查询。这既慢又容易出错
  • Java字符串是对象,具有长度并经过编码。访问或创建字符串可能需要O(n)副本
史蒂夫·威尔逊(Steve Wilson)和杰夫·凯瑟尔曼(Jeff Kesselman)于2000年在“9.2:检查JNI成本”一节中的“Java(tm)平台性能:战略和战术”中找到了一些可能已经过时的补充讨论。这大约是下降的三分之一,在下面@Philip的评论中提供


2009年IBM developerWorks的论文提供了一些关于避免JNI性能缺陷的建议。

值得一提的是,并非所有标记为
native
的Java方法都是“慢”的。他们中的一些人,这使得他们非常快。要检查哪些是固有的,哪些不是固有的,您可以在中查找
do\u inquired

(+1)好问题。在我们讨论这个问题时,我想鼓励任何做过实际基准测试的人发表他们的发现;与返回值相同。类型转换和调用堆栈编组(callstackmarshalling)是其中很好的一部分。Dave,我了解并听说过这一点。但这种转换到底是什么样的呢?那是什么东西?我正在寻找细节。使用直接ByteBuffers在Java和C之间传递数据会导致相对较低的开销。该调用需要一个适当的C堆栈框架,将所有有用的CPU寄存器推送(并将其弹出),该调用需要防护,还可以防止许多优化,如内联。此外,线程必须离开执行堆栈锁(例如,在本机代码中允许偏置锁工作)你链接到的那篇论文似乎更像是一篇性能基准论文,而不是一篇描述JNI内部工作原理的论文。@pdeva不幸的是,我找到的其他资源都链接到了java.sun.com,自收购Oracle以来,这些链接一直没有更新过。我正在寻找关于JNI内部的更多细节。这篇文章是关于Java1.3的——很久以前的事了。当时的问题是否仍然适用于Java7?声明,一些本机代码可以由JVM内联。该回答指出,一些标准本机代码是在JVM中内联的,而不是使用JNI。上面,“本机方法”是指通过JNI实现的用户定义本机方法的一般情况。感谢指向sun.misc.Unsafe的指针。我不想宣称,这种方法可以用于每个JNI调用。但知道纯字节码和纯JNI代码之间存在某种中间立场并没有什么坏处。也许这会影响一些设计决策。也许这种机制在将来会被推广。@A.H,你把内在的w/JNI搞错了。他们完全不同
sun.misc.Unsafe
和很多其他东西,比如
System.currentTimeMillis/nanoTime
都是由JVM通过“magic”处理的。它们不是JNI,它们根本没有正确的.c/.h文件,而JVM impl本身就是如此。除非您正在编写/破解JVM,否则无法遵循此方法。“”当前已断开--“这是一个工作链接。