Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三篇《How to Tune Java Garbage Collection》,本文的作者是韩国人,写在JDK 1.8发布之前,虽然有些地方有些许过时,但整体内容还是非常有价值的。译者此前也看到有人翻译了本文,发现其中有许多错漏生硬和语焉不详之处,因此决定自己翻译一份,供大家分享。
本文是“成为Java GC专家”系列文章的第三篇,在系列的第一篇文章《理解Java GC》中,我们了解到了不同GC算法的执行过程、GC的工作原理、新生代和老年代的概念、JDK 7中你需要了解的5种GC类型以及每一种GC对性能的影响。
在系列的第二篇文章《如何监控Java GC》中笔者已经解释了JVM进行实时GC的原理、监控GC的方法以及可以使这一过程更加迅速高效的工具。
在第三篇文章中,笔者将基于实际生产环境中的案例,介绍几个GC优化的最佳参数设置。在此我们假设你已经理解了本系列前两篇文章的内容,因此为了更深入的理解本文所讲内容,我建议你在阅读本篇文章之前先仔细阅读这两篇文章。
GC优化是必要的吗?
或者更准确地说,GC优化对Java基础服务来说是必要的吗?答案是否定的,事实上GC优化对Java基础服务来说在有些场合是可以省去的,但前提是这些正在运行的Java系统,必须包含以下参数或行为:
- 内存大小已经通过-Xms和-Xmx参数指定过
- 运行在server模式下(使用-server参数)
- 系统中没有残留超时日志之类的错误日志
换句话说,如果你在运行时没有手动设置内存大小并且打印出了过多的超时日志,那你就需要对系统进行GC优化。
不过你需要时刻谨记一句话:GC tuning is the last task to be done.
现在来想一想GC优化的最根本原因,垃圾收集器的工作就是清除Java创建的对象,垃圾收集器需要清理的对象数量以及要执行的GC数量均取决于已创建的对象数量。因此,为了使你的系统在GC上表现良好,首先需要减少创建对象的数量。
俗话说“冰冻三尺非一日之寒”,我们在编码时要首先要把下面这些小细节做好,否则一些琐碎的不良代码累积起来将让GC的工作变得繁重而难于管理:
- 使用
StringBuilder
或StringBuffer
来代替String
- 尽量少输出日志
尽管如此,仍然会有我们束手无策的情况。XML和JSON解析过程往往占用了最多的内存,即使我们已经尽可能地少用String、少输出日志,仍然会有大量的临时内存(大约10-100MB)被用来解析XML或JSON文件,但我们又很难弃用XML和JSON。在此,你只需要知道这一过程会占据大量内存即可。
如果在经过几次重复的优化后应用程序的内存用量情况有所改善,那么久可以启动GC优化了。
笔者总结了GC优化的两个目的:
- 将进入老年代的对象数量降到最低
- 减少Full GC的执行时间