如何优化Java垃圾回收机制4

为什么需要优化GC

或者说的更确切一些,对于基于Java的服务,是否有必要优化GC应该说,对于所有的基于Java的服务,并不总是需要进行GC优化,但前提是所运行的基于Java的系统,包含了如下参数或行为:

  • 已经通过 -Xms 和–Xmx 设置了内存大小
  • 包含了 -server 参数
  • 系统中没有超时日志等错误日志

换句话说,如果你没有设定内存的大小,并且系统充斥着大量的超时日志时,你就需要在你的系统中进行GC优化了。

但是,你需要时刻铭记一条GC优化永远是最后一项任务。

想一下进行GC优化的最根本原因,垃圾收集器清除在Java程序中创建的对象,GC执行的次数即需要被垃圾收集器清理的对象个数,与创建对象的数量成正比,因此,首先你应该减少创建对象的数量

俗话说的好,“冰冻三尺非一日之寒”。我们应该从小事做起,否则日积月累就会很难管理。

  • 我们需要使用StringBuilder 或者StringBuffer 来替代String
  • 应该尽量少的输出日志

但是,我们知道有些情况会让我们束手无策,我们眼睁睁的看着XML以及JSON解析占用了大量的内存。即便我们已经尽可能少的使用String以及尽量少的输出日志,大量的临时内存被用于XML或者JSON解析,例如10-100MB。但是,舍弃XML和JSON是很难的。我们只要知道,他会占用很多内存。

如果应用内存使用量重复几次调整之后增加了,你就可以开始GC优化了。

我为GC优化归纳了两个目的:

  1. 一个是将转移到老年代的对象数量降到最少
  2. 另一个是减少Full GC的执行时间

将转移到老年代的对象数量降到最少

按代的GC机制由Oracle JVM提供,不包括可以在JDK7以及更高版本中使用的G1 GC。换句话说,对象被创建在伊甸园空间,而后转化到幸存者空间,最终剩余的对象被送到老年代。某些比较大的对象会在被创建在伊甸园空间后,直接转移到老年代空间。老年代空间上的GC处理会新生代花费更多的时间。因此,减少被移到老年代对象的数据可以显著地减少Full GC的频率。减少被移到老年代空间的对象的数量,可能被误解为将对象留在新生代。但是,这是不可能的。取而代之,你可以调整新生代空间的大小。

减少Full GC执行时间

Full GC的执行时间比Minor GC要长很多。因此,如果Full GC花费了太多的时间(超过1秒),一些连接的部分可能会发生超时错误。

  • 如果你试图通过消减老年代空间来减少Full GC的执行时间,可能会导致OutOfMemoryError 或者 Full GC执行的次数会增加。
  • 与之相反,如果你试图通过增加老年代空间来减少Full GC执行次数,执行时间会增加。

因此,你需要将老年代空间设定为一个“合适”的值。

影响GC性能的参数

正如我们在第二篇文章结尾提到的,不要幻想“某个人设定了GC参数后性能得到极大的提高,我们为什么不和他用一样的参数?”,因为不同的Web服务所创建对象的大小和他们的生命周期都不尽相同。

简单来说,如果一个任务的执行条件是A,B,C,D和E,同样的任务执行条件换为A和B,你会觉得哪个更快?从一般人的直觉来看,在A和B条件下执行的任务会更快。

Java GC参数也是相同的道理,设定一些参数不但没有提高GC执行速度,反而可能导致他更慢。GC优化的最基本原则是将不同的GC参数用于2台或者多台服务器,并进行对比,并将那些被证明提高了性能或者减少了GC执行时间的参数应用于服务器。请谨记这一点。

下面这个表格列出了GC参数中与内存大小相关的,可以影响性能的参数。

1GC优化需要考虑的Java参数

定义

参数

描述

堆内存空间

-Xms

Heap area size when starting JVM

启动JVM时的堆内存空间。

 

-Xmx

Maximum heap area size

堆内存最大限制

新生代空间

-XX:NewRatio

Ratio of New area and Old area

新生代和老年代的占比

 

-XX:NewSize

New area size

新生代空间

 

-XX:SurvivorRatio

Ratio ofEdenarea and Survivor area

伊甸园空间和幸存者空间的占比

我在进行GC优化时经常使用-Xms,-Xmx和-XX:NewRatio。-Xms和-Xmx是必须的。你如何设定NewRatio 会对GC性能产生十分显著的影响。有些人可能会问如何设定Perm区域的大小?你可以通过-XX:PermSize 和-XX:MaxPermSize参数来设定,

当OutOfMemoryError 错误发生并且是由于Perm空间不足导致时,另一个可能影响GC性能的参数是GC类型。下表列出了所有可选的GC类型(基于JDK6.0)

2GC类型可选参数

分类

参数

备考

Serial GC

-XX:+UseSerialGC

 

Parallel GC

-XX:+UseParallelGC
-XX:ParallelGCThreads=value

 

Parallel Compacting GC

-XX:+UseParallelOldGC

 

CMS GC

-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=value
-XX:+UseCMSInitiatingOccupancyOnly

 

G1

-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC

在JDK6中这两个参数必须同时使用

除了G1 GC,可以通过每种类型第一行的参数来切换GC类型。最常用的GC类型是Serial GC。他专门针对客户端系统进行了优化。

影响GC性能的参数有很多,但是上面提到的参数会带来最显著的效果。请牢记,设定过多的参数不一定会减少GC执行时间。

你可能感兴趣的:(如何优化Java垃圾回收机制4)