垃圾收集器占用太多的CPU时间

时间:2012-03-09 09:47:56

标签: java performance garbage-collection

我开发了一个处理大量数据并需要花费大量时间才能完成的Web应用程序?

所以现在我正在对我的应用进行分析,我注意到GC的一个非常糟糕的事情 当全GC发生时,它会停止所有过程30-40秒。

我想知道是否有办法改善这一点。我不想只在GC中占用我的CPU那么多时间。以下是一些有用的细节:

  1. 我使用的是Java 1.6.0.23
  2. 我的应用程序最大内存为20 GB。
  3. 每14分钟后发生一次完整的GC。
  4. 内存之前GC为20 GB,GC之后为7.8 GB左右
  5. CPU中使用的内存(即任务管理器中显示)为41 GB。
  6. 进程完成后(JVM仍在运行)已用内存5 GB,可用内存15 GB。

5 个答案:

答案 0 :(得分:5)

现代JVM用于垃圾收集的算法很多。诸如引用计数之类的一些算法如此之快,并且诸如存储器复制之类的一些算法如此之慢。您可以更改代码,以便在大多数情况下帮助JVM使用更快的算法。

最快的算法之一是引用计数,正如名称所描述的,它计算对象的引用,当它达到零时,它就可以进行垃圾收集,之后它会减少对引用的对象的引用计数。当前的GCed对象。

为了帮助JVM使用这个算法,避免使用循环引用(对象A引用B,然后B引用C,C引用D ....,Z再次引用A)。因为即使整个对象图不可访问,对象的引用计数器也都不会达到零。

当您不再需要圆圈中的对象时(通过将null指定给引用之一),您只能打破圆圈....

答案 1 :(得分:4)

如果您使用64位架构添加:

-XX:+UseCompressedOops 64位地址转换为32位

使用G1GC代替CMS:

-XX:+UseG1GC - 它使用增量步骤

设置相同的初始和最大尺寸:-Xms5g -Xmx5g

调整参数(仅举例):

-XX:MaxGCPauseMillis=100 -XX:GCPauseIntervalMillis=1000

请参阅Java HotSpot VM Options 效果选项

答案 2 :(得分:4)

通过重复使用资源来改进应用,或者在应用的某些关键区域(无法保证帮助您)自己System.gc()。很可能你有一个内存泄漏,你必须调查,然后重组代码。

答案 3 :(得分:3)

在GC中花费的时间取决于两个因素:

  • 有多少物品存在(=可以与任何人联系)
  • 有多少个死对象实现finalize()

无法访问且不使用finalize()的对象无需花费任何费用来清理Java,这就是为什么Java通常与其他语言(如C ++)相同(并且通常更好,因为C ++花费了很多时候删除对象。)

因此,您需要在应用程序中执行的操作将减少代码中较早的对象数量和/或剪切对象(您不再需要的对象)的引用。例如:

当你有一个很长的方法时,你将保留所有从局部变量引用的对象。如果在许多较小的方法中拆分该方法,则引用将更快地丢失,并且GC将不必处理这些对象。

如果您在巨大的哈希映射中放置了您可能需要的所有内容,那么映射将使所有这些实例保持活动状态,直到代码完成为止。所以即使你不再需要它们,GC仍然需要花时间在它们上面。

答案 4 :(得分:3)

new的内容越少,需要收集的内容就越少。

假设你有A班。 您可以在其中包含对A类的另一个实例的引用。 这样你就可以制作一个A的实例的“免费列表”。 每当你需要一个A时,只需从免费列表中弹出一个。 如果空闲列表为空,则new一个。

当您不再需要它时,将其推到空闲列表中。

这可以节省很多时间。