判断对象是否存活的算法
需要回收的位置如下

其实垃圾回收是jvm自带的功能,所以有了如下的优缺点
优点:
1.项目开发的时候不需要开发人员考虑内存管理
2.可以有效的防止内存泄漏,更加高效的利用可使用的内存
3.因为垃圾回收不再有了作用于的概念
缺点:
因为不了解所以使用过程中会出现内存溢出和内存泄漏的问题
下面将判断对象存活的算法进行简单说明
引用计数算法:它的意思就是给每个创建的对象添加一个引用计数器,被引用计数值加1,引用失效时减一,当计数值为0时,表示该对象就不再被使用了
优点:
实现简单,执行效率高
缺点:
检测不到循环引用
实际案例

因为引用一直存在了,永远无法进行回收了,请注意java中的垃圾回收并没有使用引用计算算法
可达性分析算法:官方解释是通过一系列GC ROOTs 对象作为起始点,从起点开始向下搜索对象的路径,搜索所经过的路径称为引用链,当一个对象和任何一个GC ROOTs都没有引用链时,最终判断该对象不可用
先看图

再看下可以作为GC Roots的对象有哪些
1.栈帧中的局部变量表中的reference引用所引用的对象
2.方法区中static静态引用的对象
3.方法区中final常量引用的对象
4.本地方法栈中JNI(Native方法)引用的对象
5.Java虚拟机内部的引用, 如基本数据类型对应的Class对象, 一些常驻的异常对象(比如 NullPointExcepiton、
6.OutOfMemoryError) 等, 还有系统类加载器。
7.所有被同步锁(synchronized关键字) 持有的对象
8.反映Java虚拟机内部情况的JMXBean、 JVMTI中注册的回调、 本地代码缓存等

这里可达性分析算法是java判断对象存活使用的
但是这个时候的对象还并不能进入死亡,还需要再次的判断
下面通过模拟的程序进行说明


代码部分
package com.java.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.ref.PhantomReference;
import java.lang.ref.WeakReference;
/**
* @Description:
* @Author: qiuxie
* @Create: 2023/6/2 14:18
*/
public class FinalizeEscapeGc {
/**
* 定义日志对象
*/
private static final Logger logger= LoggerFactory.getLogger(FinalizeEscapeGc.class);
public static FinalizeEscapeGc SAVE_HOOK=null;
public void isAlive(){
logger.info("是的,我仍然活着");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
logger.info("finalize 方法执行中");
FinalizeEscapeGc.SAVE_HOOK=this;
}
public static void main(String[] args) {
SAVE_HOOK=new FinalizeEscapeGc();
logger.info("打印SAVE_HOOK:{}",SAVE_HOOK);
//开始第一次的自救
SAVE_HOOK=null;
System.gc();
//因为finalize()优先级比较低,设置等待0.5秒
try {
Thread.sleep(500);
if (SAVE_HOOK!=null){
logger.info("开始第一次判断是否存活");
SAVE_HOOK.isAlive();
}else {
logger.info("第一次的自救 很抱歉,我已经死亡了");
}
} catch (InterruptedException e) {
logger.error("睡眠异常:{}",e);
}
logger.info("第二次自救前 打印SAVE_HOOK:{}",SAVE_HOOK);
//只能救一次,第二次自救会失败
//开始第二次的自救
SAVE_HOOK=null;
System.gc();
//因为finalize()优先级比较低,设置等待0.5秒
try {
Thread.sleep(500);
if (SAVE_HOOK!=null){
logger.info("开始第二次判断是否存活");
SAVE_HOOK.isAlive();
}else {
logger.info("第二次的自救 很抱歉,我已经死亡了");
}
} catch (InterruptedException e) {
logger.error("睡眠异常:{}",e);
}
logger.info("最后打印SAVE_HOOK:{}",SAVE_HOOK);
}
}
pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
这个org.slf4j已经被包含在springboot了
下面给出两次标记的走向图

注意点:finalize()执行缓慢,会有发生死循环的可能性,甚至最终导致内存回收子系统的崩溃
浙公网安备 33010602011771号