JVM 垃圾收集算法 标记-清楚、标记-复制、标记-整理
摘要
Java程序在运行过程中会产生大量的对象,但是内存大小是有限的,如果光用而不释放,那内存迟早被耗尽。如C、C++程序,需要程序员手动释放内存,Java则不需要,是由垃圾回收器去自动回收。
垃圾回收器回收内存至少需要做两件事情:标记垃圾、回收垃圾。于是诞生了很多算法及垃圾回收器。
垃圾判断算法
即判断JVM中的所有对象,哪些对象是存活的,哪些对象可回收的算法。
引用计数算法
在对象中添加一个属性用于标记对象被引用的次数,每多一个其他对象引用,计数+1,当引用失效时,计数-1,如果计数=0,表示没有其他对象引用,就可以被回收。
这个算法无法解决循环依赖的问题。

可达性分析算法
通过一系列被称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系链向下搜索,如果某个对象无法被搜索到,则说明该对象无引用执行,可回收。相反,则对象处于存活状态,不可回收。
JVM中的实现是找到存活对象,未打标记的就是无用对象,GC时会回收。

哪些对象可以作为GC Root呢:
- 所有Java线程当前活跃的栈帧里指向GC堆里的对象的引用;换句话说,当前所有正在被调用的方法的引用类型的参数/局部变量/临时值。
- VM的一些静态数据结构里指向GC堆里的对象的引用,例如说HotSpot VM里的Universe里有很多这样的引用。
- JNI handles,包括global handles和local handles
- (看情况)所有当前被加载的Java类
- (看情况)Java类的引用类型静态变量
- (看情况)Java类的运行时常量池里的引用类型常量(String或Class类型)
- (看情况)String常量池(StringTable)里的引用
垃圾回收算法
1、标记-清除算法
概念:
顾名思义,标记-清除算法分为两个阶段,标记(mark)和清除(sweep)。
标记:遍历所有的GC Roots,然后将所有的GC Roots可达的对象标记为存活的对象。
清除:清除的过程将遍历所有堆中的对象,将没有标记的对象全部清除。
图解:

对上图中的黄色部分进行垃圾回收,回收后的截图如下所示:

从图中可知,进行标记清理后,可用内存增加,但是清除垃圾后的内存地址不连接,出现垃圾碎片。
缺点:
1、执行效率不稳定,如果Java堆中包含大量对象,而且大部分是需要被回收的,这时必须记性大量标记及清除动作,导致标记和清除两个过程执行效率都随对象数量增长而降低。
2、内存空间碎片化的问题,标记、清除后会产生大量的不连续内存碎片,空间碎片太可能会导致当以后需要分配大对象时无法找到足够的连续内存二不得不提前触发另一次垃圾收集动作。
2、标记-复制算法
概念:
复制算法将内存分为两个区间,这两个区间是动态的,在任意一个时间点,所有分配的对象内存只能在其中一个区间(活动区间),另外一个区间就是空闲区间。
当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址一次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。这个时候空闲内存已经变成了活动区间,垃圾对象全部在原来的活动区间,清理掉垃圾对象,原活动区间就变成了空闲区间。
这种方式内存的代价太高,每次基本上都要浪费一半的内存。于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存是Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)。
图解:


优点:
1、很好地解决了“标记-清除”算法,内存布局混乱的缺点。
缺点:
1、浪费一半的内存。
2、假设对象存活率为100%,那么“标记-复制”算法的GC过程就是重复的把对象复制一遍,而且将所有的引用地址重置一遍。可以预见的复制所消耗的时间随着对象存活率达到一定程度将会变成灾难。所以“标记-复制”算法使用的场景是可以忍受只是用50%内存,对象存活率非常低
3、标记-整理算法
概念:
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
图解:


优点:
1、弥补了“标记-清除”算法,内存区域分散的缺点
2、弥补了“标记-复制”算法内存减半的代价
缺点:
1、效率不高,对于“标记-清除”而言多了整理工作。
4、分代收集算法
当前商业虚拟机的垃圾收集都采用分代收集。此算法没啥新鲜的,就是将上述三种算法整合了一下。具体如下:
根据各个年代的特点采取最适当的收集算法
1、在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。只需要付出少量存活对象的复制成本就可以完成收集。
2、老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须用标记-清除或者标记-整理。
测试案例
以下测试采用的是Serial加Serial Old收集器组合。
查看当前jdk默认额收集器使用以下语句。
java -XX:+PrintCommandLineFlags -version
1、对象优先在Eden分配
测试代码
2、大对象直接进入老年代
3、长期存活的对象将进入老年代
4、动态年龄判断
5、空间分配担保
JVM 垃圾收集算法 标记-清楚、标记-复制、标记-整理的更多相关文章
- JVM垃圾收集算法(标记-清除、复制、标记-整理)
[JVM垃圾收集算法] 1)标记-清除算法: 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象(错了吧?) 清除阶段:清除所有未被标记的对象 2)复制算法: 将原有的内存空间 ...
- JVM垃圾收集算法之标记算法
前言 总所周知,jvm的垃圾收集算法一般包括标记.清除.整理三个阶段,最近在看了有关于垃圾收集的标记算法,记录一下自己的理解. 垃圾收集中标记算法有两种:一种是引用计数法,一种是根搜索算法. 引用记数 ...
- JVM垃圾收集算法
JVM垃圾收集 1. 判断对象是否存活 引用计数算法 对象添加一个引用计数器,每个地方引用它,计数器值加+1:当引用失效,计算器值减1:任何时刻计数器为0的对象不可能被使用.引用计数算法实现简单,高效 ...
- JVM垃圾收集算法之清除算法
最近看了一些大佬的博文,文中提到说:学习知识不能一味的死学滥学,在学之前要明白为什么要学这个知识,在实际的应用中怎么运用这个知识.我觉得说的很对,很多时候我学习确实是了解了这是什么原理,但是要说到实际 ...
- JVM——垃圾收集算法及垃圾回收器
一.垃圾回收算法 1.标记-清除算法 1)工作流程 算法分为"标记"和"清除"阶段:首先标记出所有需要回收的对象(标记阶段),在标记完成后统一回收所有被标记的对 ...
- JVM——垃圾收集算法
1.标记-清除算法 最基础的收集算法,如其名,算法为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 两个不足: 1)效率问题,标记和清除两个过程的效率 ...
- 【004】【JVM——垃圾收集算法】
Java虚拟机学习总结文件夹 垃圾收集算法 垃圾收集算法的实现涉及大量的程序细节,并且各个平台的虚拟机操作内存的方法又各不同样,介绍几种垃圾收集算法的思想及其发展过程. 标记-清除算法 垃圾收集 ...
- [jvm] -- 垃圾收集算法篇
垃圾收集算法 标记-清除算法 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 缺点: 效率问题: 空间问题(标记清除后会产生大量不连续的碎片) 复制算法 它可以将内存分为大小相同 ...
- JVM垃圾收集算法——分代收集算法
分代收集算法(Generational Collection): 当前商业虚拟机的垃圾收集都采用"分代收集算法". 这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分 ...
随机推荐
- Spark中直接操作HDFS
Spark作为一个基于内存的大数据计算框架,可以和hadoop生态的资源调度器和分布式文件存储系统无缝融合.Spark可以直接操作存储在HDFS上面的数据: 通过Hadoop方式操作已经存在的文件目录 ...
- linux的软件管理的rpm包和yum配置加tar解压包和安装编译./configuer
软件管理 rpm包 和yum 1.软件形式 Linux系统的第三方软件,无论是应用软件还是工具软件,大多以以下两种形式之一发行: 源代码形式 预编译形式 获取的源代码形式的软件,需要对其 ...
- nodeJs + js 大文件分片上传
简单的文件上传 一.准备文件上传的条件: 1.安装nodejs环境 2.安装vue环境 3.验证环境是否安装成功 二.实现上传步骤 1.前端部分使用 vue-cli 脚手架,搭建一个 demo 版本, ...
- JAVA学习:HashMap 和 ConcurrentHashMap
一.最基本的HashMap 和 ConcurrentHashMap 1.HashMap的结构和底层原理:由数组和链表组成,数组里面每个地方都存了Key-Value这样的实例,在Java7叫Entry ...
- 串行&并行&并发,同步&异步
1. 串行&并行&并发 1.1 串行 这个非常好理解,字面意思,像串成一个串一样,顺序执行 上一个没执行完的话,后面的就必须无条件等待 一般情况就是一个线程里:任务一个接一个执行,类似 ...
- 提交项目到码云上git的使用
git clone .. cd 到项目目录 git branch 查看当前的所有分支 git branch shanshan 创建一个属于自己的分支 git checkout shansha ...
- qt事件过滤器的使用(可以用于控制屏幕背光等)
在嵌入式qt项目中,有时并不需求屏幕一直亮着,需要一段时间不操作时,将屏幕背光关掉,以达到节能的目的: 在qt项目中,可以通过重写事件过滤器来实现屏幕操作的检测,加上定时器的时间控制,可以实现指定时间 ...
- ASP.NET Core3.x 基础(1)
ASP.NET Core与2.x相比发生的一些变化: 项目结构 Blazor SignalR gRPC 关于Program类:Main方法,在系统执行时就会找到这个Main方法,实际上是配置了ASP. ...
- 攻防世界-web(进阶)-upload1
打开链接是一个上传文件的窗口,随便上传一个PDF文件提示必须上传图片,查看源代码,要求必须输入png或jpg格式文件才会上传成功,想到通过修改源代码删除上传限制条件,上传一句话木马,通过中国菜刀进入后 ...
- java中三大集合框架
一.List集合 1.List实现的超级父类接口:Collection 存储一组不唯一(允许重复),有序的对象. 2.了解ArrayList类 A):定义的格式:ArrayList<具体类型&g ...