Java程序在运行一段时间后变得越来越慢

我有一个Java程序,它是一个典型的机器学习算法,通过一些方程更新一些参数的值:

for (int iter=0; iter<1000; iter++) {
    // 1. Create many temporary variables and do some computations                         
    // 2. Update the value for the parameters                    
}

更新参数的计算相当复杂,我必须创建许多临时对象,但它们不会在循环中引用。循环中的代码占用大量 CPU,并且不访问磁盘。这个程序加载了一个相对较大的训练数据集,因此,我向JVM授予了10G内存(-Xmx10G),这比它需要的要大得多(通过“top”命令或窗口的任务管理器在~6G处达到峰值)。

我在几台Linux机器(centos 6,24G内存)和一台Windows机器(win7,12G)上测试了它,这两台机器都安装了SUN Hotspot JDK / JRE 1.8。除了 -Xmx 之外,我没有指定其他 JVM 参数。这两台计算机都专用于我的程序。

在Windows上,我的程序运行良好:每次迭代都使用非常相似的运行时间。但是,所有 centos 机器的运行时间都很奇怪。它最初运行正常,但在第7/8次迭代时会显着减慢(慢约10倍),然后在每次迭代中保持慢速约10%。

我怀疑这可能是由Java的垃圾回收器引起的。因此,我使用jconsole来监视我的程序。次要GC在两台机器上都经常发生,这是因为程序在循环中创建了许多临时变量。此外,我使用了“jstat -gcutil $pid$ 1s”命令并捕获了统计信息:

Centos: https://www.dropbox.com/s/ioz7ai6i1h57eoo/jstat.png?dl=0

窗口:https://www.dropbox.com/s/3uxb7ltbx9kpm9l/jstat-winpng.png?dl=0

[编辑]但是,两种机器的统计数据差异很大:

  1. Windows 上的“S1”在 0 到 50 之间快速跳跃,而在 centos 上停留在 “0.00”。
  2. 窗口上的“E”从0到100变化非常快。当我打印每秒的统计数据时,屏幕截图不会显示其递增到100。然而,在centos上,“E”相当缓慢地增加到100,然后减少到0,并再次增加。

似乎我的程序的奇怪行为是由于Java GC?我是Java性能监视器的新手,没有优化GC参数设置的好主意。您有什么建议吗?谢谢!


答案 1

我很抱歉将此作为答案发布,但我没有足够的分数来评论。

如果您认为这是一个与GC相关的问题,我会将其更改为垃圾1收集器–XX:+UseG1GC

我发现了这个简短的解释:http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-java-8/

能否在分析下运行软件?尝试使用 jprofiler、VisualVM 甚至 netbeans profiler。它可能会对你有很大帮助。

我注意到你有自己的向量和矩阵的封装。也许你花的内存也比必要的多得多。但我不认为这是问题所在。

再次抱歉没有作为评论做出贡献。(会更合适)


答案 2

我会考虑在循环之外声明变量,以便mem分配完成一次并完全消除GC。


推荐