Java JNI 调用比预期慢(至少 2 毫秒/调用)

标签 java c performance java-native-interface

我从其他几份报告中读到,人们通常在 4-80 ns 上花费一个普通的、基本的 JNI 调用:

来自 What makes JNI calls slow?

For trivial native methods, last year I found calls to average 40 ns on my Windows desktop, and 11 ns on my Mac desktop ..

来自 Possible increase of performace using JNI?

However JNI calls often take around 30 ns ..

当我在我的 JNI 代码中调用简单方法时(简单的意思是不超过一个时间 int 返回类型 int 的参数),我得到的往返调用时间(用 System.nanoTIme 测量)在 50,000 到80,000 纳秒。

如果我对 VM 进行“预热”并在计时之前运行调用数百次,我仍然会得到大约 2000-4000 ns(低于 800-1000)。 (如上所述,我听说其他人报告 < 100 ns.. 并且在频繁调用时加起来确实比这高 10-20 倍。)

这是正常速度吗?是什么导致我的 native 代码调用速度如此之慢?

更新:

JNIEXPORT jint JNICALL Java_com_snap2d_gl_RenderControl_correctGammaNative
  (JNIEnv *env, jobject obj, jint pixel) {
    return X2D_correctGamma(pixel, 1.0f);
}

其中 X2D_correctGamma(int,float) 是一种校正像素 Gamma 值的方法(自发布以来我已经实现了 native 代码)。

Java 基准测试:

    for(int i = 0; i < 100; i++) {
        long t1 = System.nanoTime();
        correctGammaNative(0xFFF);
        long t2 = System.nanoTime();
        System.out.println(t2 - t1);
    }

这是“热身”代码。大多数 printlns 在初始调用后读取 800-1000ns。

不幸的是,我可能不得不放弃它,因为它应该用于渲染,每秒调用它数千次会使帧速率降至 1 FPS。

系统信息:

在 JDK1.6.0_32(64 位)、JDK1.7.0_04(64 位)和 JRE1.7.0_10(32 位)上表现相似

Windows 7 64 位

16GB 内存

i7-3770 四核 CPU @ 3.4-3.9ghz

GNU GCC MinGW 编译器(32 位和 64 位)

最佳答案

Is this normal speed?

没有。如果您真的每次 JNI 调用获得 50,000-80,000 ns,则说明发生了一些奇怪的事情。

What could be causing my native code to be called so much slower?

不知道。它几乎可以是任何东西。但是,如果您向我们展示 native 代码和 Java 代码,我们将能够更好地进行解释。

我的钱会花在这上面,这根本不是 JNI 调用的问题。相反,我希望它是您进行基准测试的方式的产物。您可以做(或不做)的很多事情都会导致 Java 基准测试产生虚假结果。我们需要查看您的基准测试代码。


好的,您的更新表明您之前报告的时间(50,000-80,000 或 2000-4000)不正确或不相关。考虑到以下情况,800-1000ns 的计时听起来是合理的。

我认为您的基准测试存在三个缺陷。

  • 您正在尝试测量几纳秒量级的时间间隔。但是您的测量没有考虑到调用 System.nanoTime() 需要很长时间。您需要做的是测量在每对 System.nanoTime() 调用之间进行几千或几百万次 JNI 调用所花费的时间,然后计算并打印平均值。

  • 您的代码没有将进行 JNI 调用所花费的时间与执行调用主体所花费的时间分开。 (或者也许它确实如此……而您还没有向我们展示该代码。)。我怀疑 gamma 校正将比 JNI 调用开销花费更长的时间。

  • 你的热身不够。您运行代码的时间是否足以让 JIT 编译启动是值得怀疑的。此外,您的基准代码仅限于单个方法调用这一事实意味着即使 JIT 编译器确实运行了,您也有可能d 从不调用该方法的 JIT 编译版本。将基准代码放入一个方法中,并重复调用该方法。

关于Java JNI 调用比预期慢(至少 2 毫秒/调用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14269798/

相关文章:

java - 为什么在打印出来时必须将枚举元素转换为字符串?

c - netsnmp_gethostbyname_v4 行为

ios - 在 Retina 显示器上带有 drawRect/更新图像性能问题的 UIView

algorithm - 相同长度的最长连续子列表的长度,以及子列表元素求和的奇偶性

java - JRuby on Rails + 遗留 Java 代码的最佳数据库策略是什么?

java - 在 Android Studio 中使 subView 监听双击

java - 错误对话框未被销毁

c - 以 printf 作为参数的 for 循环

c - 如何在障碍处正确同步线程

c# - 替换模板中字符串的最快方法