JVM GC调优总结


一、基本收集算法


   1. 复制:将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A。
      因为只访问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去访问死对象,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存。

优点:只访问活跃对象,遍历快

缺点:需要内存比较多,浪费一部分内存,不适合年老代
   2. 标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大,而且整理后堆里的碎片很多。

优点:不浪费内存

缺点:遍历2次,2次标记效率都不高,内存碎片多

   3. 标记整理(mark-sweep-compact):综合了上述两者的做法和优点,先标记活跃对象,然后将其合并成较大的内存块。

移动了活跃对象,回收后留下完整内存块

二 JVM GC收集器


1.Serial收集器 -XX:+UseSerialGC 复制收集算法
  单线程收集器,收集时会暂停所有工作线程(我们将这件事情称之为Stop The World,下称STW),使用复制收集算法,虚拟机运行在Client模式时的默认新生代收集器。 

2.ParNew收集器 -XX:+UseParNewGC 复制收集算法 多线程执行
  ParNew收集器就是Serial的多线程版本,除了使用多条收集线程外,其余行为包括算法、STW、对象分配规则、回收策略等都与Serial收集器一摸一样。对应的这种收集器是虚拟机运行在Server模式的默认新生代收集器,在单CPU的环境中,ParNew收集器并不会比Serial收集器有更好的效果。 

3.Parallel Scavenge收集器 -XX:+UseParallelGC 复制算法,吞吐量最大化
  Parallel Scavenge收集器(下称PS收集器)也是一个多线程收集器,也是使用复制算法,但它的对象分配规则与回收策略都与ParNew收集器有所不同,它是以吞吐量最大化(即GC时间占总运行时间最小)为目标的收集器实现,它允许较长时间的STW换取总吞吐量最大化。 

4.Serial Old收集器  -XX:+UseSerialGC 标记整理算法
  Serial Old是单线程收集器,使用标记-整理算法,是老年代的收集器,上面三种都是使用在新生代收集器。 

5.Parallel Old收集器 -XX:+UseParallelOldGC 标记整理算法多线程执行
  老年代版本吞吐量优先收集器,使用多线程和标记-整理算法,JVM 1.6提供,在此之前,新生代使用了PS收集器的话,老年代除Serial Old外别无选择,因为PS无法与CMS收集器配合工作。 

6.CMS(Concurrent Mark Sweep)收集器 XX:+UseconcMarkSweepGC 标记,置换 不压缩 算法 

压缩需要加参数-XX:CMSFullGCsBeforeCompaction(多少次FullGC后压缩内存) 或者 -XX+UseCMSCompactAtFullCollection(CMS后压缩内存)
CMS收集器使用的是标记-清除算法,也就是说它在运行期间会产生空间碎片,所以虚拟机提供了参数开启CMS收集结束后再进行一次内存压缩。 


CMS大体过程为:

      (1) 并发 gc 会先暂停 jvm 运行 , 然后标志应用中的强可达对象 ; init-mark,stop the world
      (2) 开始并发标志引用强可达对象的对象 ; 这时程序还在运行 , concurrent-mark
      (3) 因为程序正在运行 , 这时重新标志一下引用被修改的对象 ( 这时 jvm 会再次暂停 ) rescan
      (4) 重新标记后 , 堆中所有活动对象被标记出来了 , 然后开发开始回收堆中的垃圾对象 ; sweep

      (5)该算法不进行compact,而是在内存中建立一个空闲内存的链表,下次在old区分配空间时,会先找到一个符合条件的空闲空间给对象,该方式会影响old区和young区的对象空间分配,影响young区主要是由于有些young区的对象需要转至old区.

三、JVM设置需要注意的地方

1.-Xmn 与 -XX:NewRatio 不要同时设置

2.-Xss一定要设置JDK5.0以后每个线程堆栈大小为1M,对一般的应用来说,256K足够了,如果发生StackOverFlow错误,那么加大这个值也没用。

jvm 栈 和本地方法栈可能存在的异常:

StackOverFlowError:线程请求的栈深度>虚拟机所允许的深度
OutOfMemory:当扩展时无法申请到足够的内存(大部分虚拟机都允许动态扩展,java虚拟机规范也允许固定长度)


3.设置-XX:+DisableExplicitGC,避免RMI或应用显示调用System.gc().如果有此类调用gc日志中会含有System标志。

修正:

1.jdk6 u32之前存在一个bug,某些情况下,cms GC 不回收Dirent byte buffer,堆外内存。

2.使用这个参数可能会导致cms GC触发之前,堆外内存过大时,物理内存或地址空间不足,出现OOM错误。

因此建议:

1.不使用这个参数,改为:-XX:+ExplicitGCInvokesConcurrent

2.配置堆外内存最大空间:-XX:MaxDirectMemorySize。不配置时,默认与-Xmx值相同。可能造成OOM.


4.-XX:MaxTenuringThreshold 对象最多!经过多少次minor GC后进入年老代。设置为0,则不经过survior拷贝,直接进入年老代。增大此值会增加对象在Minor GC被回收的几率,减小此值会增加对象进入年老代的几率。注意最多,有可能不经过那么多次,比如

4.1.大的数组对象,如果在survivor空间中相同年龄所有对象大小的累计值大于survivor空间的一半,大于或等于个年龄的对象就可以直接进入老年代,无需达到MaxTenuringThreshold中要求的年龄

4.2.配置了 -XX:PretenureSizeThreshold 参数,则大于指定byte的对象直接进入年老代分配。


5.持久代GC时回收无引用的废弃常量与无用类。无用类需满足以下三个条件:

5.1.该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。 

5.2.加载该类的ClassLoader已经被GC。 

5.3.该类对应的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法。

是否对类进行回收可使用-XX:+ClassUnloading参数进行控制,还可以使用-verbose:class或者-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载、卸载信息。

在大量使用反射、动态代理、CGLib等bytecode框架、动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要JVM具备类卸载的支持以保证永久代不会溢出

6 -XX:CMSInitiatingOccupancyFraction=70以上  堆内存达到多少比例时,触发CMS。需要与-XX:+UseCMSInitiatingOccupancyOnly 同时使用以保证CMS不自动触发,否则不到比例也可能触发CMS.

计算公式一:CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值