jvm垃圾回收机制

^_^的我 9月前 ⋅ 377 阅读

垃圾收集器

  1. 如果说垃圾回收算法是内存回收的方法论,那么垃圾收集器就是具体实现。jvm会结合针对不同的场景及用户的配置使用不同的收集器。

    • 年轻代收集器

    Serial、ParNew、Parallel Scavenge

    -老年代收集器

    Serial Old、Parallel Old、CMS收集器

    -特殊收集器

    G1收集器[新型,不在年轻、老年代范畴内]

  2. 新生代收集器

    • Serial

    最基本、发展最久的收集器,在jdk3以前是gc收集器的唯一选择,Serial是单线程收集器,Serial收集器只能使用一条线程进行收集工作,在收集的时候必须得停掉其它线程,等待收集工作完成其它线程才可以继续工作。

    虽然Serial看起来很坑,需停掉别的线程以完成自己的gc工作,但是也不是完全没用的,比如说Serial在运行在Client模式下优于其它收集器[简单高效,不过一般都是用Server模式,64bit的jvm甚至没Client模式]

    JVM的Client模式与Server模式

    • 优点:对于Client模式下的jvm来说是个好的选择。适用于单核CPU【现在基本都是多核了】
    • 缺点:收集时要暂停其它线程,有点浪费资源,多核下显得。
  3. ParNew收集器

    可以认为是Serial的升级版,因为它支持多线程[GC线程],而且收集算法、Stop The World、回收策略和Serial一样,就是可以有多个GC线程并发运行,它是HotSpot第一个真正意义实现并发的收集器。默认开启线程数和当前cpu数量相同【几核就是几个,超线程cpu的话就不清楚了 - -】,如果cpu核数很多不想用那么多,可以通过-XX:ParallelGCThreads来控制垃圾收集线程的数量。

    • 优点:支持多线程,多核CPU下可以充分的利用CPU资源
    • 运行在Server模式下新生代首选的收集器【重点是因为新生代的这几个收集器只有它和Serial可以配合CMS收集器一起使用】
    • 缺点: 在单核下表现不会比Serial好,由于在单核能利用多核的优势,在线程收集过程中可能会出现频繁上下文切换,导致额外的开销。
  4. Parallel Scavenge 采用复制算法的收集器,和ParNew一样支持多线程。

    但是该收集器重点关心的是吞吐量【吞吐量 = 代码运行时间 / (代码运行时间 + 垃圾收集时间) 如果代码运行100min垃圾收集1min,则为99%】

    对于用户界面,适合使用GC停顿时间短,不然因为卡顿导致交互界面卡顿将很影响用户体验。

    对于后台

    高吞吐量可以高效率的利用cpu尽快完成程序运算任务,适合后台运算

    Parallel Scavenge注重吞吐量,所以也成为"吞吐量优先"收集器。

老年代收集器

  1. Serial Old

    和新生代的Serial一样为单线程,Serial的老年代版本,不过它采用"标记-整理算法",这个模式主要是给Client模式下的JVM使用。 如果是Server模式有两大用途

    • jdk5前和Parallel Scavenge搭配使用,jdk5前也只有这个老年代收集器可以和它搭配。
    • 作为CMS收集器的后备。
  2. Parallel Old

    支持多线程,Parallel Scavenge的老年版本,jdk6开始出现, 采用"标记-整理算法"【老年代的收集器大都采用此算法】

    在jdk6以前,新生代的Parallel Scavenge只能和Serial Old配合使用【根据图,没有这个的话只剩Serial Old,而Parallel Scavenge又不能和CMS配合使用】,而且Serial Old为单线程Server模式下会拖后腿【多核cpu下无法充分利用】,这种结合并不能让应用的吞吐量最大化。

    Parallel Old的出现结合Parallel Scavenge,真正的形成“吞吐量优先”的收集器组合。

  3. CMS

    CMS收集器(Concurrent Mark Sweep)是以一种获取最短回收停顿时间为目标的收集器。【重视响应,可以带来好的用户体验,被sun称为并发低停顿收集器】

    启用CMS:-XX:+UseConcMarkSweepGC

    正如其名,CMS采用的是"标记-清除"(Mark Sweep)算法,而且是支持并发(Concurrent)的

    它的运作分为4个阶段

    • 初始标记:标记一下GC Roots能直接关联到的对象,速度很快
    • 并发标记:GC Roots Tarcing过程,即可达性分析
    • 重新标记:为了修正因并发标记期间用户程序运作而产生变动的那一部分对象的标记记录,会有些许停顿,时间上一般 初始标记 < 重新标记 < 并发标记
    • 并发清除

    以上初始标记和重新标记需要stw(停掉其它运行java线程)

    之所以说CMS的用户体验好,是因为CMS收集器的内存回收工作是可以和用户线程一起并发执行。

    总体上CMS是款优秀的收集器,但是它也有些缺点。

    • cms堆cpu特别敏感,cms运行线程和应用程序并发执行需要多核cpu,如果cpu核数多的话可以发挥它并发执行的优势,但是cms默认配置启动的时候垃圾线程数为 (cpu数量+3)/4,它的性能很容易受cpu核数影响,当cpu的数目少的时候比如说为为2核,如果这个时候cpu运算压力比较大,还要分一半给cms运作,这可能会很大程度的影响到计算机性能。
    • cms无法处理浮动垃圾,可能导致Concurrent Mode Failure(并发模式故障)而触发full GC
    • 由于cms是采用"标记-清除“算法,因此就会存在垃圾碎片的问题,为了解决这个问题cms提供了 -XX:+UseCMSCompactAtFullCollection选项,这个选项相当于一个开关【默认开启】,用于CMS顶不住要进行full GC时开启内存碎片合并,内存整理的过程是无法并发的,且开启这个选项会影响性能(比如停顿时间变长)
    浮动垃圾:由于cms支持运行的时候用户线程也在运行,程序运行的时候会产生新的垃圾,这里产生的垃圾就是浮动垃圾,cms无法当次处理,得等下次才可以。
  4. G1收集器

    G1(garbage first:尽可能多收垃圾,避免full gc)收集器是当前最为前沿的收集器之一(1.7以后才开始有),同cms一样也是关注降低延迟,是用于替代cms功能更为强大的新型收集器,因为它解决了cms产生空间碎片等一系列缺陷。

    摘自甲骨文:适用于 Java HotSpot VM 的低暂停、服务器风格的分代式垃圾回收器。G1 GC 使用并发和并行阶段实现其目标暂停时间,并保持良好的吞吐量。当 G1 GC 确定有必要进行垃圾回收时,它会先收集存活数据最少的区域(垃圾优先)

    g1的特别之处在于它强化了分区,弱化了分代的概念,是区域化、增量式的收集器,它不属于新生代也不属于老年代收集器。

    用到的算法为标记-清理、复制算法

    jdk1.7,1.8的都是默认关闭的,更高版本的还不知道
    
    	开启选项 -XX:+UseG1GC 
    
    	比如在tomcat的catania.sh启动参数加上
    

    g1是区域化的,它将java堆内存划分为若干个大小相同的区域【region】,jvm可以设置每个region的大小(1-32m,大小得看堆内存大小,必须是2的幂),它会根据当前的堆内存分配合理的region大小。

    jdk7中计算region的源码,这边博主看了下也看不怎么懂,也翻了下openjdk8的看了下关于region的处理似乎不太一样。。
    

    g1通过并发(并行)标记阶段查找老年代存活对象,通过并行复制压缩存活对象【这样可以省出连续空间供大对象使用】。

    g1将一组或多组区域中存活对象以增量并行的方式复制到不同区域进行压缩,从而减少堆碎片,目标是尽可能多回收堆空间【垃圾优先】,且尽可能不超出暂停目标以达到低延迟的目的。

    g1提供三种垃圾回收模式 young gc、mixed gc 和 full gc,不像其它的收集器,根据区域而不是分代,新生代老年代的对象它都能回收。

    g1是自适应的回收器,提供了若干个默认值,无需修改就可高效运作
    	-XX:G1HeapRegionSize=n  设置g1 region大小,不设置的话自己会根据堆大小算,目标是根据最小堆内存划分2048个区域
    	-XX:MaxGCPauseMillis=200 最大停顿时间 默认200毫秒
    
  5. Minor GC、Major GC、FULL GC、mixed gc

    在年轻代Young space(包括Eden区和Survivor区)中的垃圾回收称之为 Minor GC,Minor GC只会清理年轻代.

  6. Major GC

    Major GC清理老年代(old GC),但是通常也可以指和Full GC是等价,因为收集老年代的时候往往也会伴随着升级年轻代,收集整个Java堆。所以有人问的时候需问清楚它指的是full GC还是old GC。

  7. Full GC

    full gc是对新生代、老年代、永久代【jdk1.8后没有这个概念了】统一的回收。

    【知乎R大的回答:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)、元空间(1.8及以上)等所有部分的模式】

  8. mixed GC【g1特有】

    混合GC

    收集整个young gen以及部分old gen的GC。只有G1有这个模式


全部评论: 0

    我有话说: