JVM参数
温情提示:千万不要用百度翻译翻译HandlePromotionFailure丧心病狂
-Xms :初始堆大小
-Xmx :最大堆大小
-XX:NewSize=n :设置年轻代大小
-XX:NewRatio=n: 设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3
-XX:MaxTenuringThreshold:该参数主要是控制新生代需要经历多少次GC晋升到老年代中的最大阈值。
-XX:SurvivorRatio=n :年轻代中Eden区与两个Survivor区的比值、
注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n :设置持久代大小 收集器设置
-XX:+UseSerialGC :设置串行收集器
-XX:+UseParallelGC :设置并行收集器
-XX:+UseParalledlOldGC :设置并行年老代收集器
-XX:+UseConcMarkSweepGC :设置并发收集器 垃圾回收统计信息
-XX:+PrintHeapAtGC GC的heap详情 -XX:+PrintGCDetails GC详情
-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-XX:+HandlePromotionFailure 老年代分配担保(true or false) 并行收集器设置
-XX:ParallelGCThreads=n :设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n :设置并行收集最大暂停时间
-XX:GCTimeRatio=n :设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n) 并发收集器设置
-XX:+CMSIncrementalMode :设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n :设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数
-XX: PretenureSizeThreshold 大对象直接进入老年区
触发垃圾回收的时机?
程序员不能具体控制时间,系统在不可预测的时间调用System.gc()函数
Minor GC 和 Full GC分别的触发条件
- Minor GC :回收新生代,因为新生代对象存活时间短,当一个新对象产生无法分配空间的时候,就会触发Minor GC
- Full GC :回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
Minor GC触发条件
- 当 Eden 空间满时,就将触发一次 Minor GC。在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果大于,则此次Minor GC是安全的;如果小于,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小,如果大于,则尝试进行一次Minor GC,但这次Minor GC依然是有风险的;
Full GC触发条件
- 空间分配担保失败。上面minor GC时,HandlePromotionFailure=true并且老年代最大连续空间小于历次晋升到老年代的对象的平均大小则改为进行一次Full GC。或者HandlePromotionFailure=false,也改为进行一次Full GC。
-
调用 System.gc()。只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存。
-
老年代空间不足。大对象直接进入老年代、长期存活的对象进入老年代而这个空间老年代不足,会引起GC。
什么时候会OOM(Out Of Memory)内存溢出?
GC肯定不会无限的执行下去,而且也不是GC一次或几次就肯定会解决问题。
GC与非GC时间耗时超过了GCTimeRatio的限制引发OOM(GCTimeRatio相当于给GC设置一个时间,如果超过时间就会OOM)
解决此问题常用的方法?(调优)
核心思想就两点:一是减少从新生代到老年代的数量,二是尽量降低fullGC的次数
- 通过NewRatio控制新生代老年代比例
- 通过 MaxTenuringThreshold控制进入老年前生存次数
- 。。。。。。调优有很多方式三言两语说不清,以后再单独总结。
GC的是什么样的对象?
引用计数为空或者从GCRoots没有任何引用链连接的情况下并且经过了一次标记—清除仍然没有复活的对象。
怎么判断对象是否存活?
- 引用计数器法
给对象添加一个引用计数器,每当由一个地方引用它,计数器的值就加1,当引用失效的时候,计数器的值就减1,任何时刻计数器为0的对象就是不可能在被调用。
- 可达性分析算法
通过一系列的成为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当对象到GC roots没用任何引用链相连的时候,则证明此对象不可用。
什么样的对象可以做为GCRoots:
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈引用的对象(以上引用均指强引用)
引用的分类
- 强引用就是在程序之中普遍存在的,类型Object obj=new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象
- 软引用用来描述一些还有用但并非必须的元素,对于它在系统将要发生内存溢出异常之前,会将这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存才会抛出内存溢出异常
- 弱引用用来描述非必须对象的,强度比软引用弱一些,被引用关联的对象只能生存到下一次垃圾收集产生之前。无论内存是否足够,都会回收
- 虚引用的唯一目的就是在这个对象被收集器回收的时候收到一个系统通知
没有引用链不一定会回收掉这个对象,一个对象在被GC之前都会进行两次标记
- 进行第一次标记主要是判断是否有必要调用finalize()方法,如果这个对象没有重写finalize()方法或者已经调用过一次finalize方法了就判定不用再调用finalize方法
- 第二此标记就是在第一次的基础上,如果需要调用,就进入一个队列,会有专门的执行fianlize方法的线程来处理,优先级很低。如果不用调用finalize方法,就标记上会进行GC回收
GC都做了什么?
根据新生代与老生代的特性不同,所用的清除算法也不同
- 在新生代中,每次垃圾收集时,都会发现大量对象死去,只有少量对象存活,那就使用复制算法。
- 新生代中的Survivor from与Survivor to两块区域实现了复制算法,每次回收新生代的时候,会将eden与Survivor from区域存活的对象复制到Survivor to区域,再将eden与Survivor from区域的所有内容清除掉。
- 而老年代中对象存活率高,没有额外空间对它进行分配担保,就必须要使用标记清理或者标记整理算法来进行回收。
七种收集器
新生代:Serial、PraNew、Parallel Scavenge
老生代:Serial Old、Parallel Old、CMS
整个java堆:G1收集器
1、serial收集器(复制算法)
这个收集器是一个单线程收集器,但它的单线程的意义不仅仅是它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是它在进行垃圾回收的时候,必须暂停其他所有工作线程,直到它收集结束
优点:简单高效,在单独的CPU环境下,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
2、ParNew收集器(复制算法)
Serial收集器的多线程版本,除了使用多线程进行收集之外,其他行为跟Serial收集器一致。
优点:多个线程同时清理,用户线程也是需要停止等待
3、Parallel Scavenge(复制算法)
是一个新生代收集器,它是使用复制算法的收集器,又是并行的多线程收集。
优点:清理线程可以与用户线程同时运行,用户线程不用等待
4、Serial Old(标记整理)
Serial收集器的老年代版本,使用标记整理算法
单线程,优点与Serial收集器相同
5、Parallel Old(标记整理)
Parallel Scavenge收集器的老年代版本,使用多线程和标记整理算法
多线程并行方式。
6、CMS收集器(基于标志清除算法)
- 初始标记:仅仅只是标记一下GC Roots能直接关联到对象,速度很快,需要停顿。
- 并发标记:进行GC Roots Tracing的过程,它在整个回收过程中耗时延长,不需要停顿。
- 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生移位的那部分对象的标记记录,需要停顿。
- 并发清除:不需要停顿。
7、G1收集器(标记整理+复制)
不分新老生代,整体是标记整理
新老生代内部是复制算法
- 初始标记
- 并发标记
- 最终标记:为了修正在并发标记期间由用户程序继续运作而导致标记产生移动的那部分标记记录,虚拟机将在此时间对象变化记录在线程的记住的设置日志里面,最终标记阶段需要把记住的设置日志的数据合并到Remembered Set中。这阶段需要停顿线程,但是可并行执行。
- 筛选回收:首先对各个区域中的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。此阶段实际上也可以做到与用户程序一起并发执行,但是因为只回收一部分时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。
优点:
- 空间整合:整体来看是基于“标记-整理”算法实现的收集器,从局部(两个区域之间)上来看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。
- 可预测的停顿:使使用者明确指定在一个长度为M数的时间片段内,消耗在GC上的时间不得超过N毫秒。