直击面试,聊聊 GC 机制

  • 可达性分析法

引用计数法#

引用计数法通过在对象头分配一个字段,用来存储该对象引用计数。一旦该对象被其他对象引用,计数加 1。如果这个引用失效,计数减 1。当引用计数值为 0 时,代表这个对象已不再被引用,可以被回收。

11561958-0d087ef6e036cf48.jpg

引用计数法

如上图所示,当 str 引用堆中对象时,计数值增加为 1。当 str 变为 null 时,既不再引用该对象,计数值减 1。此时该对象就可以被 GC 回收。

引用计数法只需要判断计数值,所以实现比较简单,这个过程也比较高效。但是存在一个很严重的问题,无法解决对象循环引用问题。

11561958-1919b3b733793834.jpg

引用计数法-1

从上图可以看到, a,b 不再引用堆中对象,导致计数减一。此时两个对象内部还存在互相引用,计数值不为 0,此时 GC 没办法回收该对象。

可达性分析法#

这个算法首先需要按照规则查找当前活跃的引用,将其称为 GC Roots。接着将 GC Roots 作为根节点出发,遍历对象引用关系图,将可以遍历(可达)的对象标记为存活,其余对象当做无用对象。

11561958-8044cfe1e61617e0.jpg

可达性分析

注意这里是是引用,而不是对象。

从上图可以看到,绿色对象虽然存在循环引用,但是由于这些对象不能被 GC Roots 遍历到,所以将会被回收。

可以被当做GC Roots 活跃引用包括但不限于以下引用:

  • 方法中局部变量

  • 静态变量,常量

  • JNI handles

在哪里回收垃圾#


还记得刚开始接触 Java 时,只知道堆栈,对象实例分配在堆中,方法中局部变量位于栈中。实际上 JVM 内存区域划分更加细致,分为:

  • 方法区

  • 虚拟机栈

  • 本地方法栈

  • 程序计数器

11561958-3938d35e9c4e3a71.jpg

JVM 运行时内存区域划分

如图所示,我们将内存划分为线程私有与线程共享的区域。方法区与堆都是线程共享的区域,这两部分占用 JVM 大部分内存,剩下三个小弟将会跟线程绑定,随着线程消亡,自动将会被 JVM 回收。

堆应该是大家最熟悉的一块区域,几乎所有对象实例都将会在此出生,通常也是虚拟机上占用内存最大一块区域,简直就是 JVM 内存中的大哥大。堆内存内部也不是简简单单一块而已,目前将会根据分代算法,将堆分代,不同对象位于不同区域。这一点我们下文再详细了解。

方法区

方法区将会保存已被虚拟上加载的类信息、常量,静态变量,字节码等信息,堆上的对象正式通过方法区这些信息,才能正确创建出来。

虚拟机栈栈由一系列栈帧组成,每个栈帧其实代表一个方法,栈帧中将会保存一个方法的局部变量表,方法出入口信息,操作栈等。每当调用一个方法,就将会把这个栈帧压入栈中,执行结束,出栈。

本地方法栈与虚拟机栈比较类似,最大区别在于,虚拟机栈执行的 Java 方法,而本地方法栈将会用来执行 Native 方法服务。下面方法就会在本地方法栈中执行。




Copy



`public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);`

程序计数器

程序计算器可以说是这几块区域占用最小的一部分,但是功能却十分重要。Java 源代码通过编译变成字节码,然后被 JVM 载入运行之后,将会变成一条条指令,而程序计数器的工作就是告诉当前线程下一条需要执行指令。这样即使发生了线程切换,等待恢复的时候,当前线程依然知道接下去要执行的指令。

怎么回收#


目前主流 GC 算法主要分为三种:

  • 标记-清除算法

  • 复制算法

  • 标记-整理算法

标记-清除算法#

这是一个最为基础也是最容易实现的算法,主要实现步骤分为两步:标记,清除。

  • 标记:通过上述 GC Roots 标记出可达对象。

  • 清除:清理未标记对象

11561958-74973b62715a8f26.jpg

image-20191214114722060

ps:这个图着实难画啊。。。。

可以看到经过这个算法回收之后,虽然堆空间被清理出来,但是也产生很多空间碎片。这就会导致一个新对象根据堆剩余容量计算,看起来是可以分配,但是实际分配过程,由于没有连续内存,导致虚拟机感知到内存不足,又不得不提前再次触发 GC

可能这里你就会有疑惑,为什么对象需要分配一块连续的内存?

这里引用一下 R 神 @RednaxelaFX 答案。

11561958-69217fb275483517.jpg

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

资料整理不易,点个关注再走吧

  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

[外链图片转存中…(img-DZ5RegLK-1714764110838)]

资料整理不易,点个关注再走吧

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值