垃圾回收器占用太多CPU时间



我开发了一个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

现代JVM使用许多算法进行垃圾收集。有些算法,例如引用计数,速度很快,而有些算法,如内存复制,速度很慢。您可以更改代码,以帮助JVM在大多数情况下使用更快的算法。

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

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

当你不再需要圆中的对象时,你只能打断圆(通过为其中一个引用指定null)。。。。

如果使用64位架构,请添加:

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

使用G1GC而不是CMS:

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

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

调整参数(仅示例):

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

请参阅Java HotSpot VM选项性能选项

要么通过重用资源来改进应用程序,要么在应用程序的某些关键区域自行启用System.gc()(这不能保证对您有所帮助)。最有可能的是,您在某个地方发生了内存泄漏,您必须对此进行调查,然后重新构造代码。

new的东西越少,需要收集的东西就越少。

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

当你不再需要它时,把它推到免费列表上。

这可以节省很多时间。

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

  • 有多少物体是活的
  • 有多少死对象实现finalize()

在Java中,无法访问且不使用finalize()的对象不需要花费任何费用来清理,这就是为什么Java通常与C++等其他语言不相上下(而且通常要好得多,因为C++需要花费大量时间来删除对象)。

因此,你需要在应用程序中减少存活的对象数量,和/或减少对代码早期对象(你不再需要)的引用。示例:

当您有一个非常长的方法时,您将保持从局部变量引用的所有对象都是活动的。如果将该方法拆分为许多较小的方法,则引用将更快地丢失,GC将不必处理这些对象。

如果你把你可能需要的所有东西都放在巨大的哈希映射中,这些映射将保持所有这些实例的活力,直到你的代码完成。因此,即使你不再需要这些,GC仍然需要在它们上花费时间。

最新更新