繁体   English   中英

运行一段时间后,Java程序变慢了

[英]Java program is getting slower after running for a while

我有一个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内存)和一台窗口机器(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. Windows上的“E”从0变为非常快。当我每秒打印统计数据时,屏幕截图并未显示其增量为100.然而,在“数字”上,“E”会缓慢地向100增加,然后减少到0,再次增加。

看来我的程序奇怪的行为是由于Java GC? 我是Java性能监视器的新手,并不是一个优化GC参数设置的好主意。 你有什么建议吗? 非常感谢你!

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

如果您认为这是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探查器。 它可能对你有很大帮助。

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

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

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

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

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

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

首先,在循环之外声明变量以避免使用garbace是一种常见的最佳实践。 正如'Wagner Tsuchiya'所说,如果您对GC有疑问,请尝试运行一个分析器。 如果你想要一些关于GC调整的技巧,我找到了很好的博文

您可以尝试每次迭代调用System.gc()以查看性能是上升还是下降。 这可以帮助您将其缩小到以前的一些答案诊断。

如果你的截图中显示的GC时间是几百毫秒,那么GC可能不是问题。 我建议您使用分析器来调查锁争用和IO(Netbeans很棒)。 我知道你说你的程序做了很少的IO但是有了分析(就像调试一样)你必须删除所有的假设并一步一步地去。

根据我的经验,JAVA需要足够的内存和2+ CPU。 否则,GC开始运行时CPU使用率将非常大。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM