-
java虚拟机中的垃圾回收器采用
可达性分析
来探索所有存活的对象 -
扫描堆中的对象,看是否能够
沿着GC Root对象为起点的引用链找到该对象
,找不到,表示可以回收
可以作为GC Root的对象
-
虚拟机栈(栈帧中的本地变量表)中引用的对象
-
方法区中类静态变量引用的对象
-
方法区中常量引用的对象
-
本地方法栈中JNI(即一般说的Native方法)引用的对象
======================================================================
-
强引用
-
软引用
-
弱引用
-
虚引用
-
终结器引用
下面我们分别进行描述
======================================================================
我们平时所使用的引用便是强引用,比如我们new一个对象A,把这个对象通过等号(赋值运算符)赋值给一个变量m,那么就称这个变量m强引用了刚刚的对象A
强引用的特点:
只要沿着GC root的引用链能够找到该对象,他就不会被垃圾回收,就比如上图中的C对象能找到A1对象,那么A1对象就不能被回收,当B对象和C对象对A1对象的引用都断开时,A1对象才能被垃圾回收
=======================================================================
如图,A2对象使用过软引用对象被C对象间接引用到,只要满足垃圾回收时,并且回收完内存也不够时,那么软引用所引用的A2对象就会被释放掉
所以软引用引用对象被释放
的条件是
-
没有强引用对象引用它
-
发生垃圾回收
-
垃圾回收之后内存不够
软引用的应用案例
public static void soft(){
ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
System.out.println(“循环结束:”+list.size());
for (SoftReference<byte[]> ref : list) {
System.out.println(ref.get());
}
}
list先引用软引用对象,软引用对象间接的引用byte数组
list和SoftReference之间是强引用,SoftReference和byte数组之间是软引用
内存充足的时候软引用引用的对象保留,但是当内存不足的时候,软引用引用的对象就会被清除
=======================================================================
和软引用的区别是,当弱引用引用该对象时,发生垃圾回收不管内存是否充足,弱引用所引用的对象都会被回收
public class Demo03 {
private static final int _4MB = 410241024;
public static void main(String[] args) throws IOException {
List<WeakReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
//关联了软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去
WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
list.add(ref);
for (WeakReference<byte[]> w: list){
System.out.println(w.get()+“”);
}
System.out.println();
}
System.out.println(“循环结束:”+list.size());
}
}
通过list集合引用WeakReference,通过WeakReference间接的引用byte[]数组,这样进行垃圾回收,就会尝试把WeakReference运用的byte数组所占用的内存做释放
====================================================================
当软引用所引用的对象或弱引用引用的对象被清除之后,软引用和弱引用本身并不会消失,软引用和弱引用本身也是一个对象,此时软引用和弱引用会进入引用队列
软引用和弱引用自身也要占用一定内存,如果想释放软引用和弱引用的内存,需要使用引用队列找到它们,对其做进一步的处理
引用队列操作代码
public class Demo02 {
private static final int _4MB = 410241024;
public static void main(String[] args) throws IOException {
ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
//引用队列
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
//关联了软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB],queue);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
Reference<? extends byte[]> poll = queue.poll();
while (poll != null){
list.remove(poll);
poll = queue.poll();
}
for (SoftReference<byte[]> ref : list) {
System.out.println(ref.get());
}
}
}
关联软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去,之后查看引用队列中是否有软引用,有就将其移出
======================================================================
在ByteBuffer
被回收的时候,他分配的直接内存并不能被java的垃圾回收管理,所以我们将虚引用对象Cleaner进入引用队列
,虚引用所在队列会有一个叫RefrenceHandlel
的线程,来定时到这个引用队列中找新入队的Cleaner,如果有就调用Cleaner中的clean
方法,根据记录的直接内存的地址调用Unsafe.freeMemary
方法来清理直接内存
========================================================================
所有的java对象都继承自Object
类,Object类有finallize()
终结方法,当对象重写了终结方法并且没有强引用,他就可以被当成垃圾回收,终结方法的调用依靠终结器引用
如上图当A4对象被垃圾回收时,在A4对象被真正清除
之前,终结期引用进入引用队列,再由一个优先级很低的线程(finallizeHandler)
查看引用队列中的终结器引用,通过终结器引用找到将要垃圾回收的对象,调用对象的finallize
方法,调用之后,该对象就可以被垃圾回收了
=======================================================================
========================================================================
=======================================================================
第一个阶段:标记
顺着GC Root查找没有引用的对象,将其进行标记
第二个阶段:清除
将垃圾对象所占用的空间释放
释放不意味着将每一个字节进行清理操作,清除只是把对象所占用内存的起始与结束地址记录下来,放在一个较空闲的地址链表里,下次分配内存的时候会直接覆盖这部分内存
标记清除算法的优点:
- 速度快
标记清除算法的缺点:
- 容易产生内存碎片,无法满足大对象的内存分配,造成内存溢出问题
=======================================================================
第一步:标记,和标记删除算法相同
顺着GC Root查找没有引用的对象,将其进行标记
第二步:整理
清除垃圾的过程中,它会把可用的对象向前移动,使内存更为紧凑,连续的空间更多
优点:
- 没有内存碎片,空间连续
缺点
总结
以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!
下面给大家分享下我的面试大全资料
- 第一份是我的后端JAVA面试大全
后端JAVA面试大全
- 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
- 第三份是Spring全家桶资料
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!
下面给大家分享下我的面试大全资料
- 第一份是我的后端JAVA面试大全
[外链图片转存中…(img-q8l0LrSh-1720082040745)]
后端JAVA面试大全
- 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理
[外链图片转存中…(img-9Uy51XZF-1720082040746)]
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
- 第三份是Spring全家桶资料
[外链图片转存中…(img-7nwBWpiA-1720082040747)]
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理