关于垃圾回收算法的这道面试题,几乎是所有 3 年以上的 Java 面试中必问的题目,甚至有些好一点的公司会在校招时问到面试者。那么本文就系统的讲一下垃圾回收的算法,和 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:+PrintAssemblyYouTestClass

命令可能会报错: Couldnotload hsdis-amd64.dll;librarynotloadable;PrintAssemblyisdisabled

报错解决方法:使用编译好的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的信号为止。

总结

前面讲的垃圾回收器算法属于基本功,要求面试者一定要熟练记忆的,而后面的垃圾收集器的执行细节如果加分项,如果都能融会贯通的话,Offer 就离你又进一步了。

【End】

查看更多面试题内容,请访问《Java最常见200+面试题全解析》,它包含的模块有:

  • Java、JVM 最常见面试题解析

  • Spring、Spring MVC、MyBatis、Hibernate 面试题解析

  • MySQL、Redis 面试题解析

  • RabbitMQ、Kafka、Zookeeper 面试解析

  • 微服务 Spring Boot、Spring Cloud 面试解析

扫描下面二维码付费阅读

关注下方二维码,订阅更多精彩内容。

转发朋友圈,是对我最大的支持。

经典面试题:聊一聊垃圾回收算法相关推荐

  1. 图解JVM垃圾回收算法

    1 简单介绍下----->垃圾回收概念 GC中的垃圾,指的是存在于内存中的.不会再被使用的对象.而垃圾回收就是把那些不再被使用的对象进行清除,收回占用的内存空间.如果不及时对内存中的垃圾进行清理 ...

  2. C++中经典的垃圾回收算法

    1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...

  3. JVM : 12 面试题:JVM中有哪些垃圾回收算法,每个算法各自的优劣?

    主题:新生代进行垃圾回收的时候,到底是采取一种什么样的算法进行的呢? 1.复制算法的背景引入 针对新生代的垃圾回收算法,叫做复制算法. 新生代的内存分为两块,如下图: 假设有如下代码,在 " ...

  4. java jvm垃圾回收算法_深入理解JVM虚拟机2:JVM垃圾回收基本原理和算法

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 喜欢的话麻烦点下Star哈 文章将同步到我的个人博客: www.how ...

  5. 垃圾回收概述(垃圾回收算法)

    垃圾回收概述 Java 和 C++语言的区别,就在于垃圾收集技术和内存动态分配上,C++语言没有垃圾收集技术,需要程序员手动的收集. 垃圾收集,不是Java语言的伴生产物.早在1960年,第一门开始使 ...

  6. bat判断文件是否存在_BAT面试必问题系列:JVM判断对象是否已死和四种垃圾回收算法总结...

    JVM系列: 面试题一:判断对象是否已死 判断对象是否已死就是找出哪些对象是已经死掉的,以后不会再用到的,就像地上有废纸.饮料瓶和百元大钞,扫地前要先判断出地上废纸和饮料瓶是垃圾,百元大钞不是垃圾.判 ...

  7. 胡说八道JVM—垃圾回收算法和垃圾回收器

    垃圾回收算法 引用计数器法(Reference Counting) 可达性分析 标记清除算法(Mark-Sweep) 这个算法的原理很简单,但是它却是其他算法的基础,后续的其他算法否是在这个算法的基础 ...

  8. 22-09-02 西安 JVM 类加载器、栈、堆体系、堆参数调优、GC垃圾判定、垃圾回收算法、对象的finalize机制

    这篇文章不少地方都截图了宋红康老师的课件,实在他jvm这块讲的真好.连接地址如下: 尚硅谷宋红康JVM全套教程(详解java虚拟机)_哔哩哔哩_bilibili JVM入门 1.JVM结构图 JVM是 ...

  9. JVM学习笔记(二):垃圾回收、垃圾回收算法、垃圾回收器(Serial、Parallel、CMC、G1)、内存分配原则实战

    垃圾回收 一.判断对象是否可以被回收 1.引用计数计数法 内容:在对象中添加一个引用计数器,每当有一个地方引用它,计数器就加一:当引用失效时,计数器就减一:任何时刻计数器为零的对象都是不可能在被使用的 ...

最新文章

  1. 目录config.php怎么修改域名,config.php · wlphp/基于宝塔面板api给站点新增删除域名接口 - Gitee.com...
  2. win7下不能使用dnw烧写的解决办法——韦东山嵌入式Linux学习笔记05
  3. 系统动力学9种模型_软工国际标准专栏(9)|系统和软件质量模型
  4. 【bitset 技巧 分块】bzoj5087: polycomp
  5. servlet 返回可访问文件_JavaWeb技术(4):Servlet的理解(上)
  6. UIWindow创建局部弹框
  7. ASSERT报错:error C2664: “AfxAssertFailedLine”: 不能将参数 1 从“TCHAR []”转换为“LPCSTR”...
  8. REST和RESTful有什么区别
  9. Python数据结构与算法笔记(三):查找问题——列表查找
  10. BZOJ4530:[BJOI2014]大融合
  11. 如何减少java里的分支_idea切换分支的时候,忽略一些无用的修改设置
  12. Winform中 System.Drawing.Color颜色对照表
  13. MSDN帮助文档中文
  14. Dual DSI on msm8937
  15. mac关闭虚拟内存_为什么不应该关闭Mac上的虚拟内存
  16. CSDN-markdown编辑器的使用
  17. UVA - 10066The Twin Towers(LIS)
  18. 单点登录系统中如何共享cookie
  19. 【翻译】CEDEC2014[跨越我的尸体2]跨越Stylized Rendering
  20. 基于Android的废旧物品回收APP

热门文章

  1. 等待的操作过时_不会过时的6种网站seo优化操作
  2. Pytorch:数据并行和模型并行,解决训练过程中内存分配不均衡的问题
  3. Node.js的基本使用3
  4. 148. Sort List 1
  5. 记一次,jvm 内存溢出
  6. 《Android 应用测试指南》——第2章,第2.4节包浏览器
  7. 关于JAVA中的synchronized,一段不错的解释...
  8. 科普:UTF-8 GBK UTF8 GB2312 之间的区别和关系
  9. python序列切片
  10. 书店POS机--细化迭代2--测试