关于Java中重度数学计算的问题

时间:2010-11-13 11:27:06

标签: java performance native

我在我的项目中使用Java,它进行了大量的数学计算。在项目的下一次迭代中,将添加一些更多的计算。根据我对Java的了解,我怀疑这会导致性能问题。将繁重的计算委托给Fortran或C等低级语言是明智的决定吗?我可以触发本机调用与低级语言进行通信。一旦Fortran或C执行计算,Java将采取控制措施。 这会改善表现吗?

8 个答案:

答案 0 :(得分:9)

小心不要低估现代Java VM。第一代的速度非常慢,特别是在浮点运算中,但现代的确实非常快。

话虽如此,其他选择可能会更快。

可以肯定的是,你应该运行一些基准测试。不要假设一个人比另一个人更快,得到一些具体的绩效测量结果并在此基础上做出决定。

还要考虑“原生”解决方案的额外性能(如果有的话)是否值得编写和集成它的额外麻烦。

答案 1 :(得分:6)

Java中的整数和浮点数学都是直接传递给硬件的,因此这样的计算原则上并不比C语言中的慢,或者说FORTRAN。像超常函数(sin()sqrt()log()等)这样的函数的库例程实际上是用C实现的,所以再没有理由去寻找其他库。

我希望你的问题给我们一些信息。你提到有很多计算正在进行,这就是数字运算。但是你没有告诉我们这些数字是如何组织和访问的。这可能是有趣且有用的信息。如果您使用复杂的对象结构来保存数据,那么访问这些结构需要时间。如果您的结果创建了新对象,那也很昂贵。如果使用数组,那些也是对象。 Java中的多维数组是数组的数组,通过多个维度进行索引可以解析为比其他语言慢的对象引用。虽然我没有基准来证明它,但我怀疑你可能会更好地用一维数组替换多维数组和一些“手动”索引计算。你当然最好使用固定大小的数组,可能有点松弛,而不是为每次计算创建和丢弃新数组。最后,许多面向对象的技巧使你的程序结构更“优雅”和“灵活”,往往会引入许多不必要的面向对象以及随之而来的减速。原始但简单通常更快。

一个非常简单的优化可能是简单地使用JVM的-server选项(如果可用)来获得更多预编译的好处,如果你还没有这样做的话。

我是第二个人建议您在盲目重新构建程序之前对自己的计算进行分析。在令人惊讶的地方可能存在瓶颈。

答案 2 :(得分:3)

您能想到使用并行算法吗?它可能适用于您的情况,也可能不适用,但想到指出它。

答案 3 :(得分:1)

这取决于两个因素:

  1. 您应该记住,JNI调用会有成本。如果你可以把整个计算都用在C上,那么开销可以忽略不计,你可以获得一些性能。否则,如果您要在C和Java之间来回切换,那么您就没有太大机会提高性能。
  2. 假设您有一个执行计算的函数f()。您应首先确定从C获得的性能是否确实优于Java。我含糊地回忆起一些基准C和Java的文章,它实际上声称Java在数学计算方面做得更好。但无论如何我都会对两者进行基准测试 - 至少是其中的一部分。

答案 4 :(得分:1)

您还应该使用各种VM参数。在服务器模式下运行程序,这样JIT将生成更好的代码,尝试使用不同的垃圾收集器,打开转义分析(可能更好地使用JDK 7)。

This paper可以帮助您调整程序以使用最好的JVM。

如果您决定选择原生路径,请使用JNA,这会更容易,尤其是如果您的所有计算都在一个方法调用中。

答案 5 :(得分:1)

到目前为止,所有评论都很出色。我同意原生代码应该是最后一步。

并行化是值得研究的。

所以使用其他算法,取决于你正在做什么。

没有人建议您分析代码,以找出花费的时间。在开始任何修改之前,我会得到一些数据,以确切了解正在做什么以及在哪里做。它会比猜测更好地指导你的决定。

答案 6 :(得分:0)

我建议你拭目以待......像往常一样用Java实现然后测量性能,它是好的,可接受的还是坏的?

正如Skaffman所说,现代JVM具有很高的性能,并且由于JIT编译器,它们在许多情况下比原生C 更快。

This article显示了Java和C计算之间的一些比较,它也是使用最新JVM版本的一个例子,性能明智。

答案 7 :(得分:0)

当心包装类型。为了提高性能,您最好使用原始类型,因为装箱和拆箱会占用cpu周期并增加垃圾收集器的负担。特别是盒装值的集合会产生很多开销。对于集合,我将使用性能方面的原始数组或字节缓冲区。