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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (17)

我有一个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的峰值)。

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

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

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

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

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

但是,两种机器的统计数据差别很大:

  1. 窗口上的“S1”在0到50之间快速跳转,而在centos上保持“0.00”。
  2. 窗口上的“E”变化非常迅速,从0到100.当我每秒打印一次统计数据时,屏幕截图没有显示其增量为100.但是,“E”增加得相当慢,趋于100,然后降低到100 0,并再次增加。

我的程序的怪异行为似乎是由于Java GC的缘故?我是Java性能监视器的新手,对于优化GC参数设置没有好处。你有什么建议吗?非常感谢你!

提问于
用户回答回答于

给Java(或任何垃圾收集语言)太多的内存会对性能产生不利影响。实时(被引用的)对象在内存中变得越来越稀疏,导致从主内存中更频繁地获取内存。请注意,在您向我们展示的示例中,更快的窗口比Linux 更快速完整的GC - 但GC循环(特别是全部gcs)通常对性能不利。

如果运行训练集不需要特别长的时间,那么请尝试使用不同的内存分配进行基准测试。

一个更激进的解决方案,但应该产生重大影响的解决方案是通过回收池中的对象来消除(或尽可能减少)循环内的对象创建。

用户回答回答于

如果你认为这是一个GC相关的问题,我会change Garbage 1 Collector-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分析器。它可以帮助你很多。

我注意到你有自己的矢量和矩阵封装。也许你在这方面花费了太多的内存。但我不认为这是问题。

扫码关注云+社区