🌈hello,你好鸭,我是Ethan,一名不断学习的码农,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥专栏:面试八股文||Java项目
🔥本篇概览:简述JVM的垃圾回收机制及回收对象时间
目录
3.1 简述Java垃圾回收机制?(GC是什么?为什么要GC)
3 垃圾收回
3.1 简述Java垃圾回收机制?(GC是什么?为什么要GC)
难易程度:☆☆☆
出现频率:☆☆☆
为了让程序员更专注于代码的实现,而不用过多的考虑内存释放的问题,所以,在Java语言中,有了自动的垃圾回收机制,也就是我们熟悉的GC(Garbage Collection)。
有了垃圾回收机制后,程序员只需要关心内存的申请即可,内存的释放由系统自动识别完成。
在进行垃圾回收时,不同的对象引用类型,GC会采用不同的回收时机
换句话说,自动的垃圾回收的算法就会变得非常重要了,如果因为算法的不合理,导致内存资源一直没有释放,同样也可能会导致内存溢出的。
当然,除了Java语言,C#、Python等语言也都有自动的垃圾回收机制。
3.2 对象什么时候可以被垃圾器回收
难易程度:☆☆☆☆
出现频率:☆☆☆☆
简单一句就是:如果一个或多个对象没有任何的引用指向它了,那么这个对象现在就是垃圾,如果定位了垃圾,则有可能会被垃圾回收器回收。
如果要定位什么是垃圾,有两种方式来确定,第一个是引用计数法,第二个是可达性分析算法
3.2.1 引用计数法
一个对象被引用了一次,在当前的对象头上递增一次引用次数,如果这个对象的引用次数为0,代表这个对象可回收。
String demo = new String("123");
String demo = null;
当对象间出现了循环引用的话,则引用计数法就会失效
先执行右侧代码的前4行代码
目前上方的引用关系和计数都是没问题的,但是,如果代码继续往下执行,如下图
虽然a和b都为null,但是由于a和b存在循环引用,这样a和b永远都不会被回收。
优点:
实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报OOM错误。
区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。
缺点:
每次对象被引用时,都需要去更新计数器,有一点时间开销。
浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
无法解决循环引用问题,会引发内存泄露。(最大的缺点)
3.2.2 可达性分析算法
现在的虚拟机采用的都是通过可达性分析算法来确定哪些内容是垃圾。
会存在一个根节点【GC Roots】,引出它下面指向的下一个节点,再以下一个节点节点开始找出它下面的节点,依次往下类推。直到所有的节点全部遍历完毕。
根对象是那些肯定不能当做垃圾回收的对象,就可以当做根对象
局部变量,静态方法,静态变量,类信息
核心是:判断某对象是否与根对象有直接或间接的引用,如果没有被引用,则可以当做垃圾回收
X,Y这两个节点是可回收的,但是并不会马上的被回收!! 对象中存在一个方法【finalize】。当对象被标记为可回收后,当发生GC时,首先会判断这个对象是否执行了finalize方法,如果这个方法还没有被执行的话,那么就会先来执行这个方法,接着在这个方法执行中,可以设置当前这个对象与GC ROOTS产生关联,那么这个方法执行完成之后,GC会再次判断对象是否可达,如果仍然不可达,则会进行回收,如果可达了,则不会进行回收。
finalize方法对于每一个对象来说,只会执行一次。如果第一次执行这个方法的时候,设置了当前对象与RC ROOTS关联,那么这一次不会进行回收。 那么等到这个对象第二次被标记为可回收时,那么该对象的finalize方法就不会再次执行了。
GC ROOTS:
-
虚拟机栈(栈帧中的本地变量表)中引用的对象
/**
* demo是栈帧中的本地变量,当 demo = null 时,由于此时 demo
充当了 GC Root 的作用,demo与原来指向的实例 new Demo() 断开了连接,对象被回收。
*/
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
demo = null;
}
}
-
方法区中类静态属性引用的对象
/**
* 当栈帧中的本地变量 b = null 时,由于 b 原来指向的对象与
GC Root (变量 b) 断开了连接,所以 b 原来指向的对象会被回收,
而由于我们给 a 赋值了变量的引用,a在此时是类静态属性引用,
充当了 GC Root 的作用,它指向的对象依然存活!
*/
public class Demo {
public static Demo a;
public static void main(String[] args) {
Demo b = new Demo();
b.a = new Demo();
b = null;
}
}
-
方法区中常量引用的对象
/**
* 常量 a 指向的对象并不会因为 demo 指向的对象被回收而回收
*/
public class Demo {
public static final Demo a = new Demo();
public static void main(String[] args) {
Demo demo = new Demo();
demo = null;
}
}
-
本地方法栈中 JNI(即一般说的 Native 方法)引用的对象
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈计算机科学入门系列 关注走一波💕💕
🌈🌈CSAPP深入理解计算机原理 关注走一波💕💕
🌈🌈微服务项目之黑马头条 关注走一波💕💕
🌈🌈redis深度项目之黑马点评 关注走一波💕💕
🌈🌈Java面试八股文系列专栏 关注走一波💕💕
🌈🌈算法leetcode+剑指offer 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤ 分享👥 留言💬thanks!!!
📚愿大家都能学有所得,功不唐捐!