Java堆的分类

  • 分为两类:YoungGen和OldGen。其中,YoungGen分为三部分:eden,from survivor和to survivor,比例默认是:8:1:1
  • PermGen不属于java堆的范畴 

    需要注意的是,从java8开始,PermGen已经被取消,取而代之的是metaspace,不同点在于:PermGen包含class metadata,class static variable和interned string,但是metaspace只有class metadata,另外两个(class static variable和interned string)从java8开始被移动到java堆里面

GC的分类

针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  • Partial GC:并不收集整个GC堆的模式,目前主要分为下面三类:

Young GC:只收集young gen的GC 
Old GC:只收集old gen的GC。CMS的concurrent collection就是这个模式
Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式

  • Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。Full GC进行前默认会进行一次young GC,可通过参数-XX:+ScavengeBeforeFullGC来进行配置

  • 各种GC算法及其使用方法

Young collector Old collector JVM option
Serial (DefNew) Serial Mark-Sweep-Compact -XX:+UseSerialGC
Parallel scavenge (PSYoungGen) Serial Mark-Sweep-Compact(PSOldGen) -XX:+UseParallelGC
Parallel scavenge (PSYoungGen) Parallel Mark-Sweep-Compact(ParOldGen) -XX:+UseParallelOldGC
Serial (DefNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC
-XX:-UseParNewGC
Parallel (ParNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC
G1算法适用于年轻代和老年代,使用-XX:+UseG1GC来启用

GC的触发条件

1. Young GC触发条件

  • Eden区满了,会进行Young GC,将Eden和from中存活的对象放入到to中。

2. Full GC触发条件

  • 调用System.gc时,系统建议执行Full GC,但是不必然执行
  • oldGen最大【连续空间】不足,当新生代对象转入到老年代时,如果有大对象或者大数组,那么会出现老年代空间不足的情况;
  • PermGen空间不足
  • CMS GC时出现promotion failed和concurrent mode failure 
    promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代【最大连续空间】也不足以放不下造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。
  • 统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间
  • 对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过- java -Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

CMS GC和G1 GC介绍

1. CMS GC收集过程(CMS GC是针对于老年代的GC算法)

  • CMS Initial Mark(stop-the-world):收集阶段,开始收集所有的GC Roots和直接引用到的对象【该阶段会被统计到full gc里面】;
  • CMS-concurrent-mark:这个阶段会遍历整个老年代并且标记所有存活的对象,从“初始化标记”阶段找到的GC Roots开始。并发标记的特点是和应用程序线程同时运行。并不是老年代的所有存活对象都会被标记,因为标记的同时应用程序会改变一些对象的引用等。
  • CMS-concurrent-preclean:这个阶段又是一个并发阶段,和应用线程并行运行,不会中断他们。前一个阶段在并行运行的时候,一些对象的引用已经发生了变化,当这些引用发生变化的时候,JVM会标记堆的这个区域为Dirty Card(包含被标记但是改变了的对象,被认为"dirty"),这就是 Card Marking。
  • CMS-concurrent-abortable-preclean:又一个并发阶段不会停止应用程序线程。这个阶段尝试着去承担STW的Final Remark阶段足够多的工作。这个阶段持续的时间依赖好多的因素,由于这个阶段是重复的做相同的事情直到发生aboart的条件(比如:重复的次数、多少量的工作、持续的时间等等)之一才会停止。
  • CMS Final Remark(stop-the-world):这个阶段是CMS中第二个并且是最后一个STW的阶段。该阶段的任务是完成标记整个年老代的所有的存活对象。由于之前的预处理是并发的,它可能跟不上应用程序改变的速度,这个时候,STW是非常需要的来完成这个严酷考验的阶段。【该阶段会被统计到full gc里面】;
通常CMS尽量运行Final Remark阶段在年轻代是足够干净的时候,目的是消除紧接着的连续的几个STW阶段。
  • CMS-concurrent-sweep:和应用线程同时进行,不需要STW。这个阶段的目的就是移除那些不用的对象,回收他们占用的空间并且为将来使用。
  • CMS-concurrent-reset:这个阶段并发执行,重新设置CMS算法内部的数据结构,准备下一个CMS生命周期的使用。

2. G1 GC(新生代和老年代通用的收集算法,不需要其他收集算法配合)

  • 【后续将进行补充】

一些JVM参数调整的经验和规则

  1. 年轻代大小选择

  • 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
  • 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
  • 避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
  1. 年老代大小选择

  • 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得: 并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
  • 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
  • 较小堆引起的碎片问题 因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现"碎片",可能需要进行如下配置: -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩. -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
  • 使用CMS的好处是用尽量少的新生代,经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间

关于一些参数

  • -XX:MaxTenuringThreshold=n Sets the maximum tenuring threshold for use in adaptive GC sizing. The current largest value is 15. The default value is 15 for the parallel collector and is 4 for CMS.(需要注意的是,这个参数默认为15,但是对于CMS来讲,默认为4,该段文字摘自官方文档)
  • -XX:+UseCMSCompactAtFullCollection:CMS使用标记-清除法进行垃圾回收,因此不对内存随便进行整理,使用该选项可以指定对内存碎片进行整理,该选项默认是开启的
  • -XX:+ScavengeBeforeFullGC:指定进行fullGC前进行一次young GC
  • -XX:CMSInitiatingOccupancyFraction:CMS被触发时老年代使用的比例
  • -XX:MaxGCPauseMillis=50:一次GC的最大时间,单位为ms,使用parallel scanvenge算法和G1的时候才会有效
  • -XX:PretenureSizeThreshold:超过设定的大小,那么对象将会直接被分配到老年代。单位为byte,默认为0,不开启该功能。(对于PS的收集算法,该选项无效)
  • -XX:+HandlerPromotionFailure:在Minore GC前,jvm会预估老年代最大可用的连续空间是否大于新生代所有对象总空间,如果小于,那么如果打开此开关,jvm会计算老年代最大可用的连续空间是否大于【历代】年轻代晋升到老年代所有对象的平均大小,如果小于,那么会进行Minore GC,否则,进行full GC; 如果此开关没有打开,那么会直接进行full GC,(目前根据jdk源码,该选项已经无效,jvm会直接进行上述的判断)

GC常见的几个误解:

  • 除了CMS和G1外,PSYoung Gen,DefNew,PSOldGen,ParOldGen等收集算法都需要stw。
  • STW(stop-the-world)并不等于full gc,full gc指发生在年轻代和老年代的gc。
  • CMS是发生在老年代的GC算法,但是其中的两个阶段,initial marking和final remark发生在年轻代和老年代,因此其stw属于full gc的统计数据里。
  • 当CMS运行过程中,老年代空间不够,默认会使用Serial gc进行一次full gc。

参考资料

  • https://www.zhihu.com/question/41922036/answer/93079526 RednaxelaFX的回答
  • http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
  • http://ifeve.com/useful-jvm-flags-part-7-cms-collector

Java GC相关知识的更多相关文章

  1. 【转】java NIO 相关知识

    原文地址:http://www.iteye.com/magazines/132-Java-NIO Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的 ...

  2. Java 容器相关知识全面总结

    Java实用类库提供了一套相当完整的容器来帮助我们解决很多具体问题.因为我本身是一名Android开发者,包括我在内很多安卓开发,最拿手的就是ListView(RecycleView)+BaseAda ...

  3. 4)Java容器类相关知识

    1>Array 和 Arrays:   Arrays:用来操作array的工具类,其中包含一组static函数:      equals():比较两个array 是否相等. array拥有相同元 ...

  4. Java继承相关知识总结

    Java继承的理解 一.概念: 一个新类从已有的类那里获得其已有的属性和方法,这种现象叫类的继承 这个新类称为子类,或派生类,已有的那个类叫做父类,或基类 继承的好处:代码得到极大的重用.形成一种类的 ...

  5. Java异常相关知识总结

    异常: 概述:java程序运行过程中出现的错误 常见的异常: StackOverflowError ArrayIndexOutOfBoundsException NullPointerExceptio ...

  6. Java枚举相关知识

    JAVA枚举 很多编程语言都提供了枚举的概念,但是java直到1.5之后才提出了枚举的概念,出现比这个语言本身晚10年. 主要作用是用于定义有限个数对象的一种结构(多例设计),枚举就属于多例设计并且其 ...

  7. Java——接口相关知识

    1.接口用interface来声明 //定义一个动物接口 public interface Animal{ public void eat(); public void travel(); } 2.接 ...

  8. Java多线程相关知识

    1)wait()  notify()  sleep() sleep是Thread类的函数,wait和notify是Object的函数. sleep的时候keep对象锁,wait的时候release 对 ...

  9. 应用JConsole学习Java GC

    应用JConsole学习Java GC 关于Java GC的知识,好多地方都讲了很多,今天我用JConsole来学习一下Java GC的原理. GC原理 在我的上一篇中介绍了Java运行时数据区,在了 ...

随机推荐

  1. Ansible运维自动化工具19个常用模块使用实例【转】

    一.模块列表 1.setup 2.ping 3.file 4.copy 5.command 6.shell 7.script 8.cron 9.yum 10.service 11.group 12.u ...

  2. Matlab imshow, image, imagesc 三者详细分析

    1.显示RGB图像 相同点:这三个函数都是把m*n*3的矩阵中的数值当做RGB值来显示的. 区别:imshow将图像以原始尺寸显示,image和imagesc则会对图像进行适当的缩放(显示出来的尺寸大 ...

  3. 29 内置方法 eval | exec 元类 单例

    eval与exec内置方法 将字符串作为执行目标,得到响应结果 eval常用作类型转换:该函数执行完有返回值 exec拥有执行更复杂的字符串:可以形成名称空间 eval内置函数的使用场景:   1.执 ...

  4. Python——类与对象,异常处理

    类 class C1: def setdata(self,value): self.data = value def display(self): print(self.data) class C2( ...

  5. LeetCode 21. Merge Two Sorted Lists(c++)

    要定义两个链表 判断时依次对应每一个链表的值进行判断即可. /** * Definition for singly-linked list. * struct ListNode { * int val ...

  6. Django组件-Forms组件

    Django的Forms组件主要有以下几大功能: 页面初始化,生成HTML标签 校验用户数据(显示错误信息) HTML Form提交保留上次提交数据 一.小试牛刀 1.定义Form类 from dja ...

  7. selenium自动化测试在富文本中输入信息的方法

    第一次用selenium+python编写自动测试脚本,因为页面中插入了富文本编辑,开始怎么都无法输入进去,度娘好多方法都无效,分享踩坑的经历一是为了记录一下自己的成长,二是为了给同样摸索seleni ...

  8. C#学习-接口与抽象类

    接口与抽象类的区别 1.抽象类中可以包含虚方法.非抽象方法和静态成员: 当接口中不能包含虚方法和任何静态成员,并且接口中只能定义方法,不能有具体事项,方法的具体实现由实现类完成. 2.抽象类不能实现多 ...

  9. spring boot 2.0 配置双数据源 MySQL 和 SqlServer

    参考:https://www.cnblogs.com/xiaofengfeng/p/9552816.html 安装 org.mybatis.spring.boot:mybatis-spring-boo ...

  10. jdbc crud

    最近在做一个mybatis的sql审计,所有需要原生的使用一下jdbc,基于次,复习一下自己的基础知识 github 地址: https://github.com/warriorg/nodes/tre ...