> 茫茫人海千千万万,感谢这一秒你看到这里。希望我的面试题系列能对你的有所帮助!共勉!
>
> 愿你在未来的日子,保持热爱,奔赴山海!
# 每日三道面试题,成就更好自我
> 昨天既然我们聊到了JVM,那我们继续这
一个话题吧!
## 1. JVM是如何判断对象是否可回收
垃圾收集器在做
垃圾回收的时候,首先需要判断
一个对象是存活状态还是死亡状态,死亡的对象将会被标识为
垃圾数据并等待收集器进行清除。
而判断
一个对象是否为可回收状态的常用算法有两个:引用计数器法和可达性分析算法。
* 引用计数器法:
在 Java 中,引用和对象是有关联的,通过引用计数来判断
一个对象是否可以回收。它在创建对象时关联
一个与之相对应的计数器,当此对象被使用时加 1,相反销毁时 -1。当此计数器为 0 时,则表示此对象未使用,可以被
垃圾收集器回收。其优点是
垃圾回收比较及时,实时性比较高,只要对象计数器为 0,则可以直接进行回收操作;而缺点是无法
解决循环引用的问题。
* 可达性分析算法:
主要是从GC Root的对象为起点出发,然后开始向下
搜索,
搜索走过的路径称为引用链,当
一个对象到GC Root之间没有任何引用链的时候,代表这个对象不可以用,判断为
垃圾,就会被GC回收。
在 java 中可以作为 GC Roots 的对象有以下几种:
- 虚拟机栈中引用的对象
-
方法区类静态
属性引用的对象
-
方法区常量池引用的对象
- 本地
方法栈 JNI 引用的对象

> 不错不错,既然你能知道了如何判断回收,那么
## 2. 你知道有什么
垃圾回收的常见算法吗?
*
标记清除法:
分为
标记--清除两个阶段,首先先
标记出所有需要回收的对象,然后在
标记完成后统一清除回收所有被
标记的对象。
它可能产生的问题呢
标记清除后,产生一些大量不连续的内存碎片,导致可能以后后续的大内存找不到足够的连续内存再导致提前又发生一次
垃圾收集
*
标记整理法:
基本步骤和
标记清除类似,但是多了一步整理的步骤,让所有村后的对象都向一端移动,然后清除掉不需要的内存。
它
解决了内存碎片的问题,但是需要频繁的移动存活的对象,效率就比较低了。
* 复制算法:
将可用的内存分为一半,每次只使用
一个区域。将需要存活的对象复制到另
一个对象中去。
这种
方法也是可以
解决了内存碎片问题,但是内存对半分了,而且对象存活率高的对象需要频繁复制。
基于前面的算法的话,JVM采用
一个分代算法的形式:
对于JVM的堆来说分为了新生代和老年代两个区域,而新生代也还分了eden区和两个幸存区,他们比例是8:1:1,
对于新生代来说采用了复制算法,因为对于新生代来说每次
垃圾回收的存活的对象是比较少的,所以采用复制算法较好,而老年代的话,则采用了
标记整理法。
* 首先对象会先分配在eden区,
* 然后再新生代空间不足时,会发生一次mi
nor gc算法将存活的对象复制到幸存区s1中,并使存活的对象的年龄加1,然后s1和s0交换,。
* 在对象寿命超过阈值最大15时,就会晋升至老年代。
* 而当老年代的空间不足时,会先尝试触发一次mi
nor gc,如果空间还是不足的话。就会出发full gc ,而此时的stw会更长。
> 可以,那问你最后一道:
## 3. 你知道有什么
垃圾收集器吗?
常见的
垃圾收集器有:其中用于回收新生代的收集器有Serial、PraNew、P
arallel Scavenge,而回收老年代的收集器有Serial Old、P
arallel Old、CMS,最后还有
一个可以用于回收整个Java堆的G1收集器。

作用于新生代的:
* Serial 收集器属于最早期的
垃圾收集器,也是 JDK 1.3 版本之前唯一的
垃圾收集器。它是单线程的
垃圾收集器,采用复制算法,其意味着单线程是指在进行
垃圾回收时所有的工作线程必须暂停,直到
垃圾回收结束为止。
特点是简单和高效,并且本身的运行对内存要求不高,因此它在客户端模式下使用的比较多。
* sParNew 收集器实际上是 Serial 收集器的多线程并行版本,也是采用复制算法。
* P
arallel Scavenge 收集器和 ParNew 收集器类似,它也是
一个并行运行的
垃圾回收器;不同的点在于该收集器关注的侧重点是实现
一个可以控制的吞吐量。它的计算公式是:
用户运行
代码的时间 / (
用户运行
代码的时间 +
垃圾收集的时间)。比如
用户运行的时间是 8 分钟,
垃圾回收运行的时间是 2 分钟,那么吞吐量就是 80%。P
arallel Scavenge 收集器追目标就是达到
一个可控制的吞吐量,高吞吐量可以最高效率地利用
cpu时候,尽快地完成程序的运算任务。
作用于老年代的:
* Serial Old 收集器为 Serial 收集器的老年代版本,而 P
arallel Old 收集器是 P
arallel Scavenge 收集器的老年代版本。两者都是在老年代中采用这
标记—— 整理算法。
* CMS(Concurrent Mark Sweep)以
获取最短回收停顿时间为目标,与P
arallel Scavenge 收集器不同,是基于
标记 —— 清除算法实现。它强调的是提供最短的停顿时间,因此可能会牺牲一定的吞吐量。它主要应用在 Java Web 项目中,它满足了系统需要短时间停顿的要求,以此来提高
用户的交互体验。CMS 工作机制相比其他的
垃圾收集器来说更复杂。整个过程分为以下 4 个阶段:
- 初始
标记(CMS initial mark):
标记 GC Roots 能直接关联到的对象
- 并发
标记(CMS concurrent mark):进行 GC Roots Tracing
- 重新
标记(CMS remark):修正并发
标记期
间的变动部分
- 并发清除(CMS concurrent sweep):清除 GC Roots 不可达对象,和
用户线程一起工作,不需要暂停工作线程。
作用于整个Java堆
包括新生代和老年代的。
* Garbage F
irst(简称 G1)收集器是历史发展的产物,也是一款更先进的
垃圾收集器,主要面向服务端应用的
垃圾收集器,是基于基于
标记-整理算法实现,不产生内存碎片。它将内存划分为多个 Region 分区,回收时则以分区为单位进行回收,这样它就可以用相对较少的时间优先回收包含
垃圾最多区块。此外,G1收集器不同于之前的收集器的
一个重要特点是:G1回收的范围是整个Java堆(
包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。从 JDK 9 之后也成了官方
默认的
垃圾收集器,官方也推荐使用 G1 来代替选择 CMS 收集器。
> 小伙子不错嘛!今天就到这里,期待你明天的到来,希望能让我继续保持惊喜!
注: 如果
文章有任何
错误和建议,请各位大佬尽情留言!如果这篇
文章对你也有所帮助,希望可爱亲切的您给个三连关注下,非常感谢啦!也可以微信
搜索太子爷哪吒公众号私聊我,感谢各位大佬!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。