写点什么

理解 JVM 工作机制(四) 回收策略

作者:ue4
  • 2023-05-24
    上海
  • 本文字数:1772 字

    阅读完需:约 6 分钟

回收策略

程序计数器、虚拟机栈、本地方法栈随线程而生,也随线程而灭;栈帧随着方法的开始而入栈,随着方法的结束而出栈。这几个区域的内存分配和回收都具有确定性,在这几个区域内不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。


由于堆和方法区的分配内存具有不确定性。所以,垃圾收集器着重于在这两个地方进行内存的回收。

如何知道对象不再被使用?

若一个对象不被任何对象或变量引用,那么它就是无效对象,需要被回收。

引用计数法

在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一。


缺点:引用计数并不可靠。因为如果两个对象的两个字段互相引用,即使对象无法访问,引用计数也都不为零。算法就无法回收它们。


但在 Java 中并没有使用这种方法。

可达性分析算法

所有和 GC Roots 直接或间接关联的对象都是有效对象,和 GC Roots 没有关联的对象就是无效对象。


GC Roots 是一个集合


  • 虚拟机栈中的引用对象

  • 方法区中的静态类型引用对象

  • 方法区中常量引用对象(String Table)

  • JNI 引用对象

  • 虚拟机内部引用(一些常驻对象)

  • 被同步锁(synchronized)持有的对象

对象引用

Strong reference (强引用)
Car car = new Car(22000, "silver"); //GC永远不会删除car引用对象、除非他被置为null, cat = null;
复制代码
Weak reference(弱引用)
Car car = new Car(22000, "silver");WeakReference<Car> weakCar = new WeakReference(car);
int i = 0;while (true){ if (weakCar.get() != null){ i++; System.out.println("Object is alive for "+i+" loops - "+weakCar); }else { System.out.println("Object has been collected."); break; }}
复制代码


当一个对象仅仅被 weak reference 指向, 而没有任何其他 strong reference 指向的时候, 如果 GC 运行, 那么这个对象就会被回收。


这句话是什么意思呢?


当你把 car 设置为 null 的时候,当编译器发现 car 没有引用的时候,就会触发 GC 进行回收。但就算你不把它设置为 null。如果被编译器发现它没有被使用的话一样会进行回收。

Soft reference(软引用)
Car car = new Car(22000, "silver");SoftReference<Car> referenceCar = new SoftReference(car);int i = 0;while (true){    if (referenceCar.get() != null){        i++;        System.out.println("Object is alive for "+i+" loops           - "+referenceCar);    }else {        System.out.println("Object has been collected.");        break;    }}
复制代码


软引用则只有在 JVM 内存不足时才有资格被垃圾回收器回收

Phantom Reference(虚引用)
Car car = new Car(22000, "silver");ReferenceQueue refQueue = new ReferenceQueue();PhantomReference<Car> phantomReference = new PhantomReference(car, refQueue);
if (phantomReference.get() != null){ System.out.println("Object is alive for loops - "+phantomReference);}else { System.out.println("Object has been collected.");}
复制代码


虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收



对象是否必须回收

对于可达性分析算法而言,未到达的对象并非是“非死不可”的,若要宣判一个对象死亡,至少需要经历两次标记阶段。


判定 finalize() 是否有必要执行


JVM 会判断此对象是否有必要执行 finalize() 方法,如果对象没有覆盖 finalize() 方法,或者 finalize() 方法已经被虚拟机调用过,那么视为“没有必要执行”。那么对象基本上就真的被回收了。


如果对象被判定为有必要执行 finalize() 方法,那么对象会被放入一个 F-Queue 队列中,虚拟机会以较低的优先级执行这些 finalize()方法,但不会确保所有的 finalize() 方法都会执行结束。如果 finalize() 方法出现耗时操作,虚拟机就直接停止指向该方法,将对象清除。


对象重生或死亡


如果在执行 finalize() 方法时,将 this 赋给了某一个引用,那么该对象就重生了。如果没有,那么就会被垃圾收集器清除。


任何一个对象的 finalize() 方法只会被系统自动调用一次,如果对象面临下一次回收,它的 finalize() 方法不会被再次执行,想继续在 finalize() 中自救就失效了。



参考来源:https://blog.csdn.net/mazhimazh?type=blog

发布于: 刚刚阅读数: 5
用户头像

ue4

关注

还未添加个人签名 2020-08-26 加入

还未添加个人简介

评论

发布
暂无评论
理解 JVM 工作机制(四) 回收策略_Java_ue4_InfoQ写作社区