Java实时性能

标签 java performance real-time

我正在处理需要非常高级的图像操作的 Java 项目。事实上,我正在使用 OpenCV 进行大部分操作,并且我正在使用 JNI 来封装我需要的 OpenCV 函数。我对 OpenCV 提供的性能非常满意,编写 OpenCV 代码的人值得为代码付出巨大的努力。与我对 Java 开发人员编写的代码的体验形成鲜明对比。

我开始对我的编程语言的选择持乐观态度,我的项目的第一个工作迭代运行良好,但它的性能远不及实时(每 2 秒获得大约 1 帧。)我已经做了一些优化我的代码及其帮助很大。我已经能够将帧速率提高到大约每秒 10-20 帧,这很好,但我发现要进行任何进一步的优化,我必须重写 Java 代码来做同样的事情,但 10 -20 倍效率更高。

我对 Java 开发人员很少关注性能感到震惊,尤其是在编写媒体相关类的类时。我已经下载了 OpenJDK,并且正在探索我正在使用的功能。例如Raster类下有一个函数叫getPixels(...),它获取图像的像素点。我原以为这个函数在源代码中是一个高度优化的函数,多次调用System.arrayCopy 进一步优化性能。相反,我发现的是非常“优雅”的代码,它们调用 5-6 个不同的类和 10-20 个不同的方法只是为了完成我可以在一行中完成的事情:

for (int i =0; i < n; i++) {
  long p = rawFrame[i];
  p = (p << 32) >>> 32;
  byte red = (byte) ((p >> 16) & 0xff);
  byte green = (byte) ((p >> 8) & 0xff);
  byte blue = (byte) ((p) & 0xff);
  byte val = (byte)(0.212671f * red + 0.715160f * green + 0.072169f * blue);
  data[i] = val;
  grayFrameData[i] = (val & 0x80) + (val & (0x7f)); 
}

上面的代码将图像转换为灰度并获取浮点像素数据,大约需要 1-10 毫秒。如果我想用 Java 内置函数做同样的事情,转换为灰度本身需要 200-300 毫秒,然后抓取 float 像素大约需要 50-100 毫秒。这对于实时性能来说是 Not Acceptable 。请注意,为了加快速度,我大量使用按位运算符,而 Java 开发人员却回避它。

我知道他们需要处理一般情况,但即便如此,他们不能至少提供优化选项或至少警告此代码执行速度有多慢。

我的问题是,在开发的后期(我已经有了第一次迭代,而不是我正在处理实时执行更多的第二次迭代)我是否应该硬着头皮切换到 C/C++我可以做更多的微调,或者我应该坚持使用 Java,并希望事情会变得更加实时友好,这样我就不必重写已经实现的 Java 代码来获得加速。

我真的开始厌恶 Java 的“优雅”和缓慢。类(class)的数量似乎有点过头了。

最佳答案

我用 Java 完成了计算机视觉工作,我认为它非常适合计算机视觉和实时的东西,你只需要知道如何使用它。

潜在的优化:

如果您需要帮助优化您的代码,我很乐意提供帮助——例如,我可以告诉您,通过创建一个方法您可能会获得性能提升

`public static final int getGrayScale(final int pixelRGB){
    return (0.212671f * ((pixelRGB >> 16) & 0xff) + 0.715160f * ((pixelRGB >> 8) & 0xff) + 0.072169f * ((pixelRGB) & 0xff));
}`

并在您的 for{pixels} 循环中使用它。通过使用方法调用,JVM 可以更多地优化此操作,并且可能也可以更多地优化 for 循环。

如果您有要刻录的 RAM,您可以为所有可能的 24 位像素像素颜色创建一个静态的、最终的输出灰度字节查找表。这将是大约 16 MB 的 RAM,但是您不必进行任何浮点运算,只需访问一个数组即可。这可能更快,具体取决于您使用的 JVM,以及它是否可以优化数组边界检查。

寻找类似、更快的图像处理代码的地方:

我强烈建议您查看 ImageJ 图像处理应用程序及其库的代码,特别是 ij.process.TypeConverter。就像您的代码一样,它在很大程度上依赖于使用位旋转的直接数组操作最少的额外数组创建。 Java2D 库(标准 JRE 的一部分)和 Java Advanced Imaging (JAI) 库提供了其他方法来快速直接对图像数据进行图像处理,而无需每次都自己进行操作。对于 Java2D,您只需要小心使用哪些函数。

为什么 Java2D 库如此间接:

大部分“分类”是由于支持多种颜色模型和存储格式(即 HSB 图像、基于 float 的颜色模型、索引颜色模型)。间接存在是有原因的,有时实际上可以提高性能——BufferedImage 类(例如)直接挂接到最近的 VM 中的图形内存,以使某些操作更快。间接允许它在很多时候向用户掩盖这一点。

关于Java实时性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/895725/

相关文章:

java - android游标如何从列中获取空值

performance - 可以使用哪些方法在现代x86上有效地扩展指令长度?

java - 实时游戏服务器最有效的 Java 实现是什么?

java - String.concat() 不进行连接

java - 仅包含文件的扫描仪 VS 包含 FileReader 和文件的扫描仪

c++ - 为什么 accumulate 比简单的 for 循环更快?

mysql - 提高 MySQL 中的 SELECT 性能

ruby-on-rails - 为什么我的 Angular 应用程序不向我的 Entangle rails Controller 发送参数?

real-time - 如何重置 Ada.Real_Time.Clock?

java - 更适合我的情况的技术 - Adob​​e/AIR/Flex 还是 Google SDK?