JVM(四)垃圾回收的实现算法和执行细节
全文共 1890 个字,读完大约需要 6 分钟。
上一篇我们讲了垃圾标记的一些实现细节和经典算法,而本文将系统的讲解一下垃圾回收的经典算法,和Hotspot虚拟机执行垃圾回收的一些实现细节,比如安全点和安全区域等。
因为各个平台的虚拟机操作内存的方法各不相同,且牵扯大量的程序实现细节,所以本文不会过多的讨论算法的具体实现,只会介绍几种算法思想及发展过程。
垃圾回收算法
1、标记-清除算法
标记-清除算法是最基础的算法,像它的名字一样算法分为“标记”和“清除”两个阶段,首先需要标记出所需要回收的对象,标记完成后统一收集被标记的对象。
优点: 实现简单。
缺点: 产生不连续的内存碎片;“标记”和“清除”的执行效率都不高。
标记-清除算法执行过程图:
(本文图片来自《深入理解Java虚拟机》)
2、复制算法
复制算法就是将内存分为大小相同的两块,当这一块使用完了,就把当前存活的对象复制到另一块,然后一次性清空当前区块。
优点: 执行效率高。
缺点: 空间利用率低, 因为复制算法每次只能使用一半的内存。
3、标记-整理算法
也称标记-压缩算法,标记-整理算法采用和标记清除算法一样的对象“标记”,但后续不会对可回收对象进行清理,而是将存活的对象往一端空闲空间移动,然后清理边界以外的内存空间。
优点: 解决了内存碎片问题,比复制算法空间利用率高。
缺点: 因为有局部对象移动,相对效率不高。
标记-整理算法执行过程图:
4、分代收集算法
目前商用虚拟机都采用的是分代收集的算法,这种算法按照对象存活周期把内存分为几块,一般Java中分为新生代和老年代。把存活率低的对象分到新生代使用复制算法提高垃圾回收的性能,老年代则存放存活率搞的对象,使用标记-清除和标记-整理的算法,提高内存空间使用率。
新生代和老生代的具体介绍和参数配置,后续的文章会详细讲解。
垃圾回收执行细节
本节将详细的介绍一下HotSpot虚拟机在执行垃圾回收时的一些细节,目的是让读者更好的理解Java虚拟机。
HotSpot虚拟机: 它是Sun JDK和OpenJDK自定的虚拟机,也是目前使用最广泛的虚拟机。
垃圾回收流程: Java虚拟机在内存回收之前,为了保证内存的一致性,必须先暂停程序的执行,也就是传说中的Stop The World(简称STW),在使用可达性分析算法枚举GC Roots,标记出死亡对象,再进行垃圾回收。
垃圾回收遇到的问题: 那既然是要暂停程序的运行,就一定要保证停止的时间足够短,并且可控,不然带来的灾难将是毁灭性的。
解决方案: 显然HotSpot在设计的时候也考虑到了这个问题,所以在JIT编译的时候就会使用OopMap数据结构来记录栈和寄存器上的引用,这样虚拟机就直接知道了那些地方存放着对象的引用,如下图,为我编译String.hashCode()方法的部分本地代码:
可以看出,使用OopMap数据结构存储了普通对象的指针引用。
查看汇编的方法,启动命令行执行:java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly YouTestClass
命令可能会报错:Could not load hsdis-amd64.dll; library not loadable; PrintAssembly is disabled
报错解决方法:使用编译好的hsdis.dll放到:jre安装目录\bin\server目录下即可,hsdis.dll地址地址:https://pan.baidu.com/s/1-D6u0gnUx291LXS3bHOorA
安全点(Safepoint)
在OopMap的协助下,HotSpot可以快速的完成GC Roots枚举,但导致OopMap内容变化的指令很多,而且如果给每个对象生成对应的OopMap,会造成大量额外的空间,这会导致GC成本很高,所以HotSpot只会在“特定的位置”生成对应的OopMap,这些位置就成为“安全点”。
HotSpot也并不是任何时刻都会停顿下来进行GC,只会在程序都到底安全点之后才会GC,所以安全点的设置不能太少,让GC等待时间太长,也不能太多增大运行时的成本。
安全点的两种线程中断方式
抢断式中断:不需要线程的执行代码去主动配合,当发生GC时,先强制中断所有线程,然后如果发现某些线程未处于安全点,恢复程序运行,直到进入安全点为止。
主动式中断:不强制中断线程,只是简单地设置一个中断标记,各个线程在执行时轮询这个标记,一旦发现标记被改变(出现中断标记)时,那么将运行到安全点后自己中断挂起。目前所有商用虚拟机全部采用主动式中断。
安全区域(Saferegion)
安全点机制仅仅是保证了程序执行时不需要太长时间就可以进入一个安全点进行 GC 动作,但是当特殊情况时,比如线程休眠、线程阻塞等状态的情况下,显然HotSpot不可能一直等待被阻塞或休眠的线程正常唤醒执行;此时就引入了安全区的概念。
安全区(Saferegion):安全区域是指在一段区域内,对象引用关系等不会发生变化,在此区域内任意位置开始GC都是安全的;线程运行时,首先标记自己进入了安全区,然后在这段区域内,如果线程发生了阻塞、休眠等操作,HotSpot发起GC时将忽略这些处于安全区的线程。当线程再次被唤醒时,首先他会检查是否完成了GC Roots枚举(或这个GC过程),如果完成了就继续执行,否则将继续等待直到收到可以安全离开的Safe Region的信号为止。
参考
《深入理解Java虚拟机》
《垃圾回收的算法与实现》
最后
关注公众号,发送“gc”关键字,领取《垃圾回收的算法与实现》学习资料。
JVM(四)垃圾回收的实现算法和执行细节的更多相关文章
- 【JVM】垃圾回收的四大算法
GC垃圾回收 JVM大部分时候回收的都是新生代(伊甸区+幸存0区+幸存1区).按照回收的区域可以分成两种类型:Minor GC和Full GC(MajorGC). Minor GC:只针对新生代区域的 ...
- JVM(四) 垃圾回收
1. 堆内存结构 Java堆从GC的角度可以细分为:新生代(Eden区.From Survivor区和To Survivor区)和老年代. 1.1 新生代 新生代是用来存放新生的对象.一般占据堆的1/ ...
- JVM学习--(四)垃圾回收算法
我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. stop the world 在介绍垃圾 ...
- jvm的垃圾回收算法
一.对象存活判断判断对象是否存活一般有两种方式:1.引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,无法解决对象相互循环引用的问题.2 ...
- JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)
相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题,有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制中的知识点呢?没时间捋也没关系,因为小编接下来会给你捋一捋. 一. 技术 ...
- 深入理解JVM一垃圾回收算法
我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. 一.stop the world 在介绍 ...
- jvm详情——3、JVM基本垃圾回收算法回收策略
JVM基本垃圾回收算法回收策略 引用计数(Reference Counting):比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的 ...
- JVM(九):垃圾回收算法
JVM(九):垃圾回收算法 在本文中,我们将从概念模型的角度探讨 JVM 是如何回收对象,包括 JVM 是如何判断一个对象已经死亡,什么时候在哪里进行了垃圾回收,垃圾回收有几种核心算法,每个算法优劣是 ...
- JVM G1垃圾回收算法简要介绍
JVM G1垃圾回收算法简要介绍 G1的特点 能够像CMS垃圾回收算法一样并发操作应用线程(潜台词:多核) 无需太长时间即可压缩空闲内存空间(潜台词:不会引起太多的GC停顿时间) 尽可能地让GC时长可 ...
随机推荐
- Shell 编程注意点
(一)判断语句 [$# -lt 4 ]判断语句,格式[空格 比较对象1 比较符号 比较对象2] $# 启动脚本时携带参数个数;参数个数总数. $1 代表第一个参数. $? 最后一次执行名命令的退出状态 ...
- google 历史版本浏览器下载
传送门: https://www.portablesoft.org/google-chrome-legacy-versions/
- 浏览器url地址殊字符转义编码
网址URL中特殊字符转义编码字符 - URL编码值 空格 - %20" - %22# - %23% - ...
- async与defer
<script>元素的几种常见属性: async 异步加载,立即下载,不应妨碍页面其他操作,标记为 async 的异步脚本并不保证按照指定的先后顺序执行,因此异步脚本不应该在加载期间修改 ...
- java从pdf中提取文本
一(单文件转换):下载pdfbox包,百度搜pdfbox.(fontbox-1.8.16.jar和pdfbox-app-1.8.16.jar) package pdf; import java.io. ...
- Python函数式编程之lambda表达式
一:匿名函数的定义 lambda parameter_list: expression 二:三元表达式 条件为真时返回的结果 if 条件判断 else 条件为假的时候返回的结果 三:map map(f ...
- Python基础之迭代器、生成器
一.迭代器: 1.迭代:每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值.例如:循环获取容器中的元素. 2.可迭代对象(iterable): 1)定义:具有__ite ...
- ABP入门系列(3)——领域层定义仓储并实现
ABP入门系列目录--学习Abp框架之实操演练 一.先来介绍下仓储 仓储(Repository): 仓储用来操作数据库进行数据存取.仓储接口在领域层定义,而仓储的实现类应该写在基础设施层. 在ABP中 ...
- 深入理解Spring Redis的使用 (五)、常见问题汇总
目前我所知道的Redistemplate里面,我没有使用到的就是管道.这个可以进行批量的读写.类似于jdbc的batch.还有就是Redis的集群部署.但是由于我业务里没有这种需求,所以没有使用无法给 ...
- Java实现堆排序和计数排序
堆排序代码: 思想:每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最小堆,依次类推,最终得到排序的序列. import java.util.Arrays; /** * 思路:首先要 ...