2、垃圾收集器实现
上面算法都是理论性的东西,Java虚拟机规范没有规定垃圾收集器具体如何实现,因此不同厂商、不同版本虚拟机提供的垃圾收集器可能有所差异。下面列举HotSpot(Sun JDK和Open JDK自带)虚拟机提供的六种垃圾收集器实现:
收集器名称 | 应用目标 | 采用算法 | 引入版本 | 运行方式 |
Serial | 新生代 | 复制算法 | Jdk1.3.1前 | 串行,单线程 |
ParNew | 新生代 | 复制算法 | 并行,多线程 | |
Parallel Scavenge | 新生代 | 复制算法 | Jdk1.4 | 并行,多线程 |
Serial Old | 旧生代 | 标记-整理 | 串行,单线程 | |
Parallel Old | 旧生代 | 标记-整理 | Jdk1.6 | 并行,多线程 |
CMS | 旧生代 | 标记-清除 | Jdk1.5 | 并发,多线程 |
并行(Parallel):多条垃圾收集线程并行工作,而用户线程仍处于等待状态。
并发(Concurrent):垃圾收集线程与用户线程一段时间内同时工作(不是并行,而是交替执行)。
总结:
1、两个串行收集器、三个并行收集器、一个并发收集器。
2、ParNew收集器是Serial的多线程版本。
3、Serial Old收集器是Serial收集器的旧生代版本。
4、Parallel Scavenge收集器以吞吐量为目标,适合在后台运算而不需要太多交互的任务。
5、Parallel Old收集器是Parallel Scavenge的旧生代版本。
6、Parallel Scavenge收集器和Parallel Old收集器是名副其实的“吞吐量优先”组合。
7、除CMS外,其他收集器工作时都需要暂停其他所有线程,CMS是第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集器线程与 用户线程同时工作,是一款以最短停顿时间为目标的收集器,适合交互性较多的场景,这也是与Parallel Scavenge/Parallel Old吞吐量优先组合的区别。
8、新生代因为回收留下的对象少,所以采用标记-复制法。
9、旧生代因为回收留下的对象多,所以采用标记-清除/标记-整理算法。
3、选择所需垃圾收集器
虚拟机提供了参数,以便用户根据自己的需求设置所需的垃圾收集器:
JVM运行参数 | 新生代 | 旧生代 |
-XX:+UseSerialGC(Client模式默认值) | Serial | Serial Old |
-XX:+UseParNewGC | ParNew | Serial Old |
-XX:+UseConcMarkSweepGC | ParNew | CMS(Serial Old备用) |
-XX:+UseParallelGC(Server模式默认值) | Parallel Scavenge | Serial Old |
-XX:+UseParallelOldGC | Parallel Scavenge | Parallel Old |
二、性能调优2.1 性能调优的目的
减少minor gc的频率、以及full gc的次数。
2.2 性能调优的手段
1.使用JDK提供的内存查看工具,如JConsole和Java VisualVM
2.控制堆内存各个部分所占的比例
3.采用合适的垃圾收集器
手段1:内存查看工具和GC日志分析
n -verbose.gc:显示GC的操作内容。打开它,可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。
n -xx:+printGCdetails:详细了解GC中的变化。
n -XX:+PrintGCTimeStamps:了解这些垃圾收集发生的时间,自JVM启动以后以秒计量。
n -xx:+PrintHeapAtGC:了解堆的更详细的信息。
手段2:针对新生代和旧生代的比例
如果新生代太小,会导致频繁GC,而且大对象对直接进入旧生代引发full gc
如果新生代太大,会诱发旧生代full gc,而且新生代的gc耗时会延长
建议新生代占整个堆1/3合适,相关JVM参数如下:
n -Xms:初始堆大小
n -Xmx:最大堆大小
n - Xmn:新生代大小
n -XX:PermSize=n:持久代最大值
n -XX:MaxPermSize=n:持久代最大值
n -XX:NewRatio=n:设置新生代和旧生代的比值。如:为3,表示新生代与旧生代比值为1:3,新生代占整个新生代旧生代和的1/4。
手段3:针对Eden和Survivor的比例
如果Eden太小,会导致频繁GC。
如果Eden太大,会导致大对象直接进入旧生代,降低对象在新生代存活时间。
n -XX:SurvivorRatio=n:新生代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
n -XX:PretenureSizeThreshold:直接进入旧生代中的对象大小,设置此值后,大于这个参数的对象将直接在旧生代中进行内存分配。
n -XX:MaxTenuringThreshold:对象转移到旧生代中的年龄,每个对象经历过一次新生代GC(Minor GC)后,年龄就加1,到超过设置的值后,对象转移到旧生代。
手段4:采用正确的垃圾收集器
通过JVM参数设置所使用的垃圾收集器参考前面的介绍,这里关注其他一些设置。
并行收集器设置
n -XX:ParallelGCThreads=n:设置并行收集器收集时并行收集线程数。
n -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间,仅对ParallelScavenge生效。
n -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比,仅对Parallel Scavenge生效。
并发收集器设置
n -XX:CMSInitiatingOccupancyFraction:默认设置下,CMS收集器在旧生代使用了68%的空间后就会被激活。此参数就是 设置旧生代空间被使用多少后触发垃圾收集。注意要是CMS运行期间预留的内存无法满足程序需要,就会出现concurrent mode failure,这时候就会启用Serial Old收集器作为备用进行旧生代的垃圾收集。
n -XX:+UseCMSCompactAtFullCollection:空间碎片过多是标记-清除算法的弊端,此参数设置在FULL GC后再进行一个碎片整理过程
n -XX:CMSFullGCsBeforeCompaction:设置在若干次垃圾收集之后再启动一次内存碎片整理
几个参数设置的意义:
xms/xmx:定义YOUNG+OLD段的总尺寸,ms为JVM启动时YOUNG+OLD的内存大小;mx为最大可占用的YOUNG+OLD内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
NewSize/MaxNewSize:定义YOUNG段的尺寸,NewSize为JVM启动时YOUNG的内存大小;MaxNewSize为最大可占用的YOUNG内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
SurvivorRatio:设置YOUNG代中Survivor空间和Eden空间的比例
申请一块内存的过程:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收);释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区/OLD区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”
我们的一种resin服务器的jvm参数设置:
“-Xmx2000M -Xms2000M -Xmn500M -XX:PermSize=250M -XX:MaxPermSize=250M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=60 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log”
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!