减少Java垃圾收集时出现的奇怪性能影响

时间:2016-06-08 14:03:30

标签: java performance garbage-collection jvm jvm-hotspot

在对我的程序进行简单重构以减少垃圾收集时,我遇到了一些奇怪的效果。结果是不相关的代码总是慢了大约20%。

场景非常简单:我有一个方法层次结构,方法A调用方法B,B调用C1和C2。 A在循环中调用B. Ab,B C1和C2用于构建大型树结构。

我需要在C1和C2之间传递数据,所以我在B中创建了一个缓冲区对象,我首先传入C1以初始化它,然后进入C2以使用它。由于B被称为大约5,000,000次,这导致相当多的GC,显然大约是170MB的GC。

作为优化,我决定在A中创建缓冲区对象,然后将其传递给B以在C1和C2中使用。

结果:GC的数量下降到接近0。 但是,我有几个与A并行的方法(从不调用A,B,C1或C2),它们访问由A,B,C1,C2创建的相同数据。使用优化时,所有这些访问方法的性能都会降低约20%。

我有两个怀疑,但我不确定如何确认它们:

  1. 我知道JVM可以重构内存中的对象,以优化内存局部性并提高CPU缓存性能。感冒是个问题吗?
  2. 方法签名变得更大。如果参数列表超过某个阈值,JVM(或一般的CPU)是否有限制使方法调用更加昂贵?
  3. 我正在使用Oracle JVM 64bit -Xmx28G -XX:+ UseConcMarkSweepGC,其中使用了大约5GB。 我运行了两个不同的变种几十次,结果非常清楚。运行时间差异约为20%,超过30次运行的标准偏差约为1%。两个版本的程序行为都是正确的。

    如何解释这种行为? JVM内存重新排序可能是解释,还是已知存在陷阱,方法中的参数数量增加?我该如何找到?

    修改

    回答一些评论:

    我开始使用jitwatch,看起来非常好,但显然非常低级别。

    定时不应该干扰,定时/输出方法每隔几秒钟只调用一次。

    缓冲区只是long[3](其他测试从2到15左右不等)。在一个场景中,我确实在A中保留了对缓冲区的引用,因此GC按预期为0。但是,即使我在每次调用时都在A中重新创建了缓冲区,GC仍然是0 ....

0 个答案:

没有答案