1.标记清除算法

黑色部分代表可回收对象,灰色部分代表存活对象,绿色部分代表未使用的。
最基础的收集算法就是标记清除算法如同他名字一样,算法分为"标记"和"清除"两个阶段:首先标记出所有需要回收的对象,在标记完成后同一回收所有被标记的对象,
标记的过程就是我们之前讲过的可达性分析算法。当需要回收时,我们把黑色标记的部分进行回收。
标记算法优缺点:
优点:简单直接易懂
缺点:
1、空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集动作。
例如每个格子都是1K,要分配5k怎么办?只能提前进行垃圾收集了。
2、效率问题:标记和清除两个过程效率都不高。

2.复制算法

为了解决效率的问题,"复制算法"应用而生,复制算法过程:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块内存用完了,
就将还存活者的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是针对整个半区进行内存回收,
内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。
优缺点:
优点:实现简单,运行高效。
缺点:1、这种算法的代价时将内存缩小了原来的一半,代价内存利用率不高。
2、在对象存活率较高时就要进行较多的复制操作,效率将会降低

3、标记整理算法

为了解决复制算法的这些缺点,提出了标记整理算法。标记整理算法过程:标记过程仍然与"标记—清除"算法一样,

但后续的步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

4、分代收集算法
每种算法都有优缺点:那GC采用什么算法?把算法都用上,集百家之所长。为什么JVM的GC要分代收集?因为对象存过周期不同,IBM研究过,百分之90以上的对象都是"朝生夕死",生存周期很短,不到10%需要长期存活,按照这样的对象存活时间就可以分为两个区:新生代和老年代。老年代是指存活超过一定时间的,存活时间指对象活过多少次(默认为15次)GC,就成为老年代。
基本上我们所有new出的所有对象都是在新生代进行分配。新生代又分为不同的区段:Eden区(伊甸园)和Survivor区(幸存者)。新生代采用的算法是复制算法,因为百分之90以上的对象都是"朝生夕死",所以大部分对象真正存活的对象不多,需要移动的对象也不多,同时复制算法内存整理后内存非常规整。

新生代分为1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1,为啥默认会是这个比例,因为一般情况下新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。
在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold 来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

新生代的垃圾回收叫minor gc,老年代的gc叫做 major gc,整个堆的gc叫做full gc。
老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用"标记清除"或者"标记整理" 算法来进行回收。

新生代垃圾收集器:

从图中可以看出新生代的垃圾收集器有三种,都是采用的复制算法。

Stop-The-World:Java中一种全局暂停的现象,全局停顿,所有Java代码停止,native代码可以执行,但不能和JVM交互多半由于GC引起

Serial 新生代的单线程垃圾回收,采用复制算法,进行垃圾回收时,工作线程必须停止, 会产生Stop the world 现象。

ParNew垃圾收集器是Serial,收集器的多线程版本,搭配CMS垃圾回收器的首选

ParallelScavenge类似ParNew,更加关注吞吐量,达到一个可控制的吞吐量;本身是Server级别多CPU机器上的默认GC方式,主要适合后台运算不需要太多交互的任务;

老年代的垃圾收集器:

SerialOld:jdk7/8默认的老生代垃圾回收器Client模式下虚拟机使用

ParallelOld:ParallelScavenge收集器的老年代版本,为了配合Parallel Scavenge的面向吞吐量的特性而开发的对应组合;在注重吞吐量以及CPU资源敏感的场合采用

CMS:尽可能的缩短垃圾收集时用户线程停止时间;缺点在于:1.内存碎片2.需要更多cpu资源3.浮动垃圾问题,需要更大的堆空间
重视服务的响应速度、系统停顿时间和用户体验的互联网网站或者B/S系统。互联网后端目前cms是主流的垃圾回收器;

G1:JDK1.7才正式引入,采用分区回收的思维,基本不牺牲吞吐量的前提下完成低停顿的内存回收;可预测的停顿是其最大的优势;
面向服务端应用的垃圾回收器,目标为取代CMS

新生代收集器有3种,老年代收集器有三种,那么是不是任意搭配就可以?其实是不可以的那么怎么搭配使用呢?其实只有在分代收集示意图中连线了的才可以搭配一起使用。

那么如何查看本机的垃圾回收器是哪种收集器?打开命令窗口输入命令:java -XX:+PrintCommandLineFlags -version,运行会得到如下图的结果:

-XX:+UseParallelGC就指明了新生代使用ParallerGC收集器(Parallel Scavenge也叫Paraller),老年代使用Serial Old收集器。
-XX:+UseSerialGC :Serial/Serial Old收集器这样组合,新生代和老年代都用串行收集器。
-XX:+UseParallerOldGC:新生代使用Parallel Scavenge,老年代使用Parallel Old
-XX:+UseConcMarkSweepGC ,表示新生代使用ParNew,老年代的用CMS。

JVM 的GC算法和垃圾收集器的更多相关文章

  1. JVM(二)GC算法和垃圾收集器

    前言 垃圾收集器(Garbage Collection)通常被成为GC,诞生于1960年MIT的Lisp语言.上一篇介绍了Java运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线 ...

  2. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  3. JVM之GC算法、垃圾收集算法——标记-清除算法、复制算法、标记-整理算法、分代收集算法

    标记-清除算法 此垃圾收集算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记对象,它的标记过程前面已经说过——如何判断对象是否存活/死去 死去的对象就会 ...

  4. JVM初探- 内存分配、GC原理与垃圾收集器

    JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...

  5. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  6. JVM性能优化系列-(2) 垃圾收集器与内存分配策略

    2. 垃圾收集器与内存分配策略 垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如 ...

  7. 3-JVM垃圾回收算法和垃圾收集器

    垃圾回收算法和垃圾收集器 1.什么是垃圾回收 对于内存当中无用的对象进行回收,如何去判断一个对象是不是无用的对象. 引用计数法: 每个对象中都会存储一个引用计数,每增加一个引用就+1,消失一个引用就- ...

  8. [JVM-3]Java垃圾回收(GC)机制和垃圾收集器选择

    哪些内存需要回收? 1.引用计数法 这个算法的实现是,给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再被使用的.这 ...

  9. 深入理解JVM(5)——HotSpot垃圾收集器详解

    HotSpot虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,没有最好的垃圾收集器,只有最适合的垃圾收集器.根据新生代和老年代各自的特点,我们应该分别为它们选择不同的收集器,以提升垃圾回收效率. ...

随机推荐

  1. JavaScript函数式编程究竟是什么?

    摘要: 理解函数式编程. 作者:前端小智 原文:JS中函数式编程基本原理简介 Fundebug经授权转载,版权归原作者所有. 在长时间学习和使用面向对象编程之后,咱们退一步来考虑系统复杂性. 在做了一 ...

  2. python 环境配置的导入与导出

    Python——配置环境的导出与导入   导出Python环境安装包[root@bogon ~]# pip freeze > packages.txt这将会创建一个 packages.txt文件 ...

  3. select子句

    1.order by order by 字段1 升序或者降序,字段2 升序或者降序(dsc) 默认 升序(asc) 注意:如果是分组,则应该使用对分组字段进行排序的groupby语法 group by ...

  4. SQL server 无法更新标识列

    若是数据库设置了自增长字段,相应的Model也要做标记,否则修改数据的时候会提示无法更新条目 /// <summary> /// 自增长ID /// </summary> [D ...

  5. 01-Redis 简单介绍

    Redis 简单介绍 1.Redis 是什么 Redis 是一种基于键值对的 NoSQL 数据库,与很多键值对数据库不同, redis 中的值可以有 string, hash , list , set ...

  6. unsigned int数据类型最大数

    #include <stdio.h> int main() { unsigned , b = ; ) { a++; } printf( ); unsigned ; do { n = n / ...

  7. pytest文档30-功能用例与自动化用例完美对接(allure)

    前言 做自动化做久了,经常会思考一个问题,到底别人是怎么做的自动化,跟自己的有啥不一样,看过不少书和资料,都是停留在demo的层面. 真正把自动化做的好的大牛又不屑于分享自己的劳动成果,所以大部分情况 ...

  8. 201871010105-曹玉中《面向对象程序设计(java)》第十四周学习总结

    201871010105-曹玉中<面向对象程序设计(java)>第十四周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  9. 在 Oracle 中使用正则表达式

    Oracle使用正则表达式离不开这4个函数: 1.regexp_like 2.regexp_substr 3.regexp_instr 4.regexp_replace 看函数名称大概就能猜到有什么用 ...

  10. Slack完整教学与上手心得:找到正确的团队沟通之道

    Slack完整教学与上手心得:找到正确的团队沟通之道 时间 2015-06-13 09:21:42 逐鹿网 原文  http://www.zhulu.com/article/5519.html 主题 ...