当前位置: 首页 > news >正文

Java如何判断堆区中的对象可以被回收了?

如何判断堆区中的对象可以被回收了


在Java中,垃圾回收机制会帮助我们自动回收不再被使用的对象,已到达即使释放内存的效果,但是Java又是怎么知道哪些对象不会再被我们继续使用了呢,希望你通过本篇文章,理解引用计数法与可达性分析法的运行方式

垃圾回收机制

在C/C++中,一个对象如果不再使用,就要手动将其释放掉,但是很多程序员在编写程序的时候经常忘记将一些对象回收,从而就导致了内存泄漏
在Java中为了简化对象的内存释放,引入了自动的垃圾回收机制,通过垃圾回收器把不再使用的对象完成自动回收,垃圾回收器主要负责堆上的内存回收,那么垃圾回收器又是如何知道哪些对象可以被回收了呢?

在Java中,一个对象是否可以被回收,主要是看这个对象是否被引用,如果对象被引用了,说明对象还在使用,是不可以被回收的,比如说如下代码中,堆内存中的Demo对象被demo引用,那么堆中的Demo对象就不会被回收:

public class Demo {public static void main(String[] args) {Demo demo = new Demo();}
}
栈内存
堆内存
main的栈帧
demo 引用
Demo对象

若此时将demo的引用设置为null:

demo = null;

那么此时Demo对象就处于了没有被引用的状态:

栈内存
main的栈帧
demo 引用
堆内存
Demo对象

此时Demo会被垃圾回收器进行回收,那么垃圾回收器又是怎么知道Demo对象目前没有被引用呢???


引用计数法

引用计数法会为每一个对象维护一个引用计数器,当对象被引用时加一,取消引用时减一,在上面的代码中,demo引用了堆上的Demo对象,所以Demo对象的引用计数器就加一,当把demo赋值为null的时候,也就是取消了Demo的引用,此时Demo对象引用计数器将减一成为0,此时垃圾回收器就认为Demo对象此时没有被任何引用,可以回收

栈内存
堆内存
main的栈帧
demo 引用
Demo对象
引用计数器:1

但是此时会出现一个问题,如果我new了两个对象A与B,并且A对象与B对象的互为彼此的成员变量,那么就会出现循环引用的现象,此时A对象被栈内存中的a1引用,也被B对象中的a变量引用,那么他的引用技术器应该为2:

public class Demo {public static void main(String[] args) {A a1 = new A();B b1 = new B();a1.b = b1;b1.a = a1;}
}
class A {B b;
}
class B {A a;
}
栈内存
堆内存
main的栈帧
A对象
B对象
a1
b1
a
B计数器:2
b
A计数器:2

那么此时,我取消a1、b1对A与B的引用

a1 = null;
b1 = null;

我们已经无法在程序中获取到A与B对象了,因为他们两个除了彼此间的引用关系,已经没有任何引用能够找到他们,所以按照常理来说,A与B对象都不会在程序中再使用了,理应被垃圾回收器进行回收,但是又由于存在彼此间的引用关系,引用计数器的值并不是0,那么此时垃圾回收器又会认为A与B都存在被引用的关系,所以并不会回收这两个类

栈内存
main的栈帧
a1
b1
堆内存
A对象
B对象
b
a
A计数器:1
B计数器:1

那么这种情况显然是不对的,无法回收的对象有可能会导致内存泄漏,所以Java并没有使用这种方法来判断类是否应该被回收,而是使用了另外一种方式


可达性分析法

Java使用的是可达性分析算法来判断对象是否可以被回收
可达性分析法将对象分为两类:

  • 垃圾回收根对象(GC Root)
  • 普通对象

对象与对象之间存在引用关系,形成一个引用链, 可达性分析算法就是指GC Root对象到某个对象间是可达的,即从GC Root对象开始,通过引用对象可以找到的对象爱国,即认为该对象还不能被回收

GC Root对象
普通对象
对象A
对象B
对象C
对象D

此时B、C、D对象都可以通过引用被GC Root对象找到,即他们都是可达的,所以不会被视为可回收的对象,但是如果对象A与对象B之间取消引用关系,那么即使对象C与对象D任然存在引用关系,但他们是不可达的,因此他们会被回收

GC Root对象
对象A
普通对象
对象B
对象C
对象D

Java虚拟机会持有一个所有GC Root对象的列表,用来判断哪些对象是不可达的,不可达的对象将被垃圾回收器进行回收:

再次回看上面的案例,如果使用可达性分析法,那么堆内存中应该存在一个GC Root对象引用了主线程里面mian方法的栈帧中的对象,此时如果a1与b1不再引用堆中的对象,那么就算A对象与B对象存在引用关系,但是他们是不可达的,就会被视为等待回收的对象:

堆内存
A对象
B对象
栈内存
main的栈帧
a1
b1
GC-Root对象
a
b

那么哪些对象可以被当中GC Root对象呢?
主要有四种GC Root对象:

  1. 线程Thread对象
    引用线程栈帧中的方法、参数、局部变量等等,上面我们的案例中就是线程Thread对象引用了mian方法栈帧中的a1与b1
  2. 类加载器加载到的java.lang.Class对象
    引用类中的静态变量
  3. 监视器对象
    用来保存同步锁synchronized关键字持有的对象
  4. 本地方法方法调用时使用的全局对象
    由Java虚拟机来控制调用

感谢您的阅读!文章到这里就结束了,如有错误,敬请指出。

  • 如果对你有帮助请点一个关注!
  • 希望能再次见到您!
http://www.lryc.cn/news/454554.html

相关文章:

  • .Net 6.0 监听Windows网络状态切换
  • UE4 材质学习笔记01(什么是着色器/PBR基础)
  • 算法 | 位运算(哈希思想)
  • 前端提升方向
  • 深度学习基础—残差网络ResNets
  • 鸿蒙ArkUI实战开发-主打自研语言及框架
  • HDU Sit sit sit (区间DP+组合数)
  • Qt开发技巧(十四)文字的分散对齐,设置动态库路径,进度条控件的文本,文件对话框的卡顿,滑块控件的进度颜色,停靠窗体的排列,拖拽事件的坑
  • VirtulBOX Ubuntu22安装dpdk23.11
  • 线性代数书中求解齐次线性方程组、非齐次线性方程组方法的特点和缺陷(附实例讲解)
  • 初识算法 · 双指针(2)
  • React常见面试题目
  • 图解网络OSI模型与TCP/IP
  • 15分钟学 Python 第31天 :Web Scraping
  • 前端编程艺术(2)----CSS
  • 前端的全栈混合之路Meteor篇(二):RPC方法注册及调用
  • 重学SpringBoot3-集成Redis(三)之注解缓存策略设置
  • 【C++11】新特性
  • 【游戏模组】重返德军总部2009高清重置MOD,建模和材质全部重置,并且支持光追效果,游戏画质大提升
  • CGLib动态代理和JDK动态代理Demo、ASM技术尝鲜
  • [C++]使用纯opencv部署yolov11-pose姿态估计onnx模型
  • python you-get下载视频
  • SCUC博客摘录「 储能参与电能市场联合出清:SCUC和SCED模型应用于辅助服务调频市场(IEEE39节点系统)」2024年10月6日
  • Git分支-团队协作以及GitHub操作
  • 力扣刷题 | 两数之和
  • [C#]winform部署官方yolov11-obb旋转框检测的onnx模型
  • 【GC日志和OOM日志分析】JVM GC日志和OOM Dump文件分析
  • 【电路】1.1 实际电路和电路模型
  • Vue - 打包部署
  • spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)