我开发了一个Web应用程序,它处理大量数据,需要花费大量时间才能完成
所以现在我正在分析我的应用程序,我注意到GC有一件非常糟糕的事情
当发生完全GC时,它会停止所有进程30-40秒
我想知道是否有什么方法可以改进这一点。我不想只在GC中占用CPU那么多时间。以下是一些有用的细节:
- 我使用的是Java 1.6.0.23
- 我的应用程序最多占用20 GB内存
- 每14分钟发生一次完整的GC
- GC之前的内存为20 GB,GC之后的内存为7.8 GB
- CPU中使用的内存(即显示在任务管理器中)为41 GB
- 进程完成后(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仍然需要在它们上花费时间。