JVMGC学习笔记(二)

xiaoxiao2025-11-20  10

JVM GC

JVM垃圾回收学习笔记垃圾对象的判断和可触及性:*`3种可触及性的状态`**`finalize()->对象的复活`**`引用和可触及性的强度`* 垃圾回收的停顿现象

JVM垃圾回收学习笔记

垃圾对象的判断和可触及性:

3种可触及性的状态

可触及的:从根节点开始,可以到达这个对象。可复活的:对象的所有引用都被释放,但是对象有可能在finalize()函数中复活。不可触及的:对象的finalize()函数被调用,并且没有复活,那么就进入不可触及的状态,不可触及的对象不可能被复活,因为finalize()函数一个对象的生命周期中只会被调用一次。

以上三种状态中,只有在对象不可触及是才可以被安全的回收。

finalize()->对象的复活

对象通过finalize()函数来复活自己。如下例子:

public class FinalizeObjectDemo { public static FinalizeObjectDemo demo; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("FinalizeObjectDemo finalize called"); demo = this; } @Override public String toString() { return "I am FinalizeObjectDemo"; } public static void main(String[] args) throws InterruptedException { demo = new FinalizeObjectDemo(); demo = null; System.gc(); Thread.sleep(1000); if (demo == null) { System.out.println("demo is null"); }else{ System.out.println("demo is object"); } System.out.println("second GC"); demo = null; System.gc(); Thread.sleep(1000); if (demo == null) { System.out.println("demo is null -"); }else{ System.out.println("demo is object -"); } } }

控制台输出:

FinalizeObjectDemo finalize called demo is object second GC demo is null -

如上例子所示结果证明,finalize()导致引用外泄,对象复活,此时对象又变为可触及的状态。但是每个对象的生命周期只会调用一次finalize()函数。所以第二次GC时,则完成了GC的安全回收。

注意:不推荐使用finalize()函数来释放资源。

由于finalize()函数有可能发生引用外泄,无意中复活对象。由于finalize()函数是被系统调用的,不能准确的把控调用。因此用于资源的释放不是一个明智的方案。推荐使用try-catch-finally语句中进行资源的释放。

引用和可触及性的强度

java中存在四个级别的引用:强引用,软引用,弱引用,虚引用

以上四种,除了强引用之外,其他三种在一定的条件下,均可以被回收。

强引用-不可回收的引用

强引用则是程序中常用的引用类型。都是可触及,可达的。

下面的例子则是一个强引用:

public class ReferenceDemo { public static void main(String[] args) { //强引用 StringBuffer stringBuffer = new StringBuffer("hello world"); //强引用 StringBuffer stringBuffer1 = stringBuffer; System.out.println(stringBuffer == stringBuffer1); } } 控制台输出结果:true

上述例子中,两个引用都属于强引用,强引用具有以下特点:

强引用可以直接访问对象。强引用所指向的对象,在任何时候都不会被回收。强引用可能导致内存泄露。

软引用-可被回收的引用

软引用是比强引用弱一点的引用类型,当一个对象只持有软引用时,当堆空间不足时,则可以进行回收。

下面的例子演示了当Heap的内存空间不足时被回收启动参数设置:-Xmx10m:

import java.lang.ref.ReferenceQueue; public class SoftRefQueue { public static class User{ private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "[id:"+this.id+",name:"+this.name+"]"; } } //创建一个软引用队列 static ReferenceQueue<User> softQueue = null; public static class UserSoftReference extends java.lang.ref.SoftReference<User> { int uid; public UserSoftReference(User referent, ReferenceQueue<? super User> q) { super(referent, q); uid=referent.id; } } public static void main(String[] args) throws InterruptedException { Thread thread =new Thread(()->{ while (true) { if (softQueue != null) { UserSoftReference obj = null; try { obj = (UserSoftReference) softQueue.remove(); } catch (InterruptedException e) { e.printStackTrace(); } if (obj != null) { System.out.println("user id :"+obj.uid+" is delete"); } } } }); thread.setDaemon(true); thread.start(); User user = new User(1, "james"); softQueue = new ReferenceQueue<User>(); UserSoftReference userSoftReference = new UserSoftReference(user,softQueue); user = null; System.out.println(userSoftReference.get()); System.gc(); System.out.println("GC After"); System.out.println(userSoftReference.get()); System.out.println("try to create byte array and GC"); byte[] bytes = new byte[1024 * 940 * 7]; System.gc(); System.out.println(userSoftReference.get()); Thread.sleep(1000); } } 控制台输出: [id:1,name:james] GC After [id:1,name:james] try to create byte array and GC user id :1 is delete null

以上的例子说明了,在堆内存资源正常的时候,软引用的对象不一定会被回收,但是在内存资源紧张的情况下,软引用的对象还是会被回收的。所以,软引用的对象时不会出现OOM的问题。

上述例子中出现的软引用队列:ReferenceQueue,当软引用对象的被回收时,软引用对象则被引入到Queue中去。本例子中开启一个守护线程轮询判断当前软引用对象是否被回收,当软引用被回收时加入这个队列中,则可以通过当前队列来跟踪对象的回收情况。

弱引用-发现即回收

弱引用是比软引用还弱的一种引用类型。在GC回收时,只要碰见弱引用则立即回收。弱引用在被GC回收时,回收的对象也会被加入到一个注册的引用队列中去,这点和软引用很相似。下面是代码举例:

public class WeakReferenceDemo { public static class User{ private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "[id:"+this.id+",name:"+this.name+"]"; } } public static void main(String[] args) { User user = new SoftRefQueue.User(11, "James"); WeakReference<User> userWeakReference = new WeakReference<User>(user); user = null; System.out.println(userWeakReference.get()); System.gc(); System.out.println(userWeakReference.get()); } } 控制台输出结果: [id:11,name:James] null

上述例子说明无论是否内存资源足够与否,弱引用碰见都是立即回收的。

虚引用-对象回收跟踪

**虚引用:**虚引用是所有引用类型中最弱的一个。虚引用随时都会被GC回收。虚引用使用时必须和队列一起使用。它的作用就在于跟踪垃圾回收过程。下面的例子说明虚引用:

import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; public class TraceCanReliveObj { public static TraceCanReliveObj obj; static ReferenceQueue<TraceCanReliveObj> queue = null; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("obj is GC"); obj= this; } @Override public String toString() { return "I am TraceCanReliveObj"; } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ while (true) { if (queue != null) { PhantomReference<TraceCanReliveObj> objs = null; try { objs = (PhantomReference<TraceCanReliveObj>) queue.remove(); } catch (InterruptedException e) { e.printStackTrace(); } if (objs!= null) { System.out.println("objs is delete by GC"); } } } }); thread.setDaemon(true); thread.start(); queue = new ReferenceQueue<TraceCanReliveObj>(); obj = new TraceCanReliveObj(); PhantomReference<TraceCanReliveObj> traceCanReliveObjPhantomReference = new PhantomReference<TraceCanReliveObj>(obj,queue); obj = null; System.gc(); Thread.sleep(1000); if (obj == null){ System.out.println("GC is finish"); }else{ System.out.println("GC is failure"); } System.out.println(" the second GC"); obj = null; System.gc(); Thread.sleep(1000); if (obj == null){ System.out.println("GC is finish"); }else{ System.out.println("GC is failure"); } } } 控制台输出: obj is GC GC is failure the second GC objs is delete by GC GC is finish 启动参数输入:-XX:+PrintGCDetails来查看GC日志GC的回收情况

上述例子说明:虚引用可以跟踪对象的回收,因此,可以将一些资源的释放操作放置在虚引用中执行和记录。

垃圾回收的停顿现象

*垃圾回收器的任务:*识别和回收垃圾对象进行内存清理。

*STW(Stop-The-World):*在GC时候的系统短暂性的停顿,为了保证系统中不会有新的垃圾出现。同时停顿保证了系统状态在某一瞬间的一致性。也有益于垃圾回收器更好的标记垃圾对象。

JVM GC 学习笔记(一) JVM GC 学习笔记(三)

参考书籍:《实战Java虚拟机—JVM故障诊断与性能优化》

转载请注明原文地址: https://www.6miu.com/read-5039963.html

最新回复(0)