java中四大引用类型
如有不对请大佬指正
在Java中,有四种主要的引用类型,它们在垃圾回收过程中具有不同的行为和生命周期。这四种引用类型是:
强引用
-
强引用(Strong Reference)是Java中最常见的引用类型。如果一个对象具有强引用,即存在一个强引用变量引用它,那么即使内存空间不足,垃圾回收器也不会回收该对象。只有当没有任何强引用指向对象时,它才会被判定为垃圾并进行回收。
强引用使用简单,通常在代码中直接使用对象的变量来创建强引用。例如:
Object obj = new Object(); // 强引用
在上述代码中,变量
obj
持有对Object
对象的强引用。只要obj
变量存在,即使在方法结束后,Object
对象仍然可达,不会被垃圾回收器回收。强引用的特点包括:
- 生命周期长:强引用的生命周期与其变量的生命周期相同,只有在变量被显式地置为
null
或超出作用域时,对象才会成为候选的垃圾对象。 - 不可被回收:只要存在强引用指向对象,垃圾回收器不会回收该对象,即使内存空间紧张。
- 对象可直接访问:通过强引用,可以随时访问和操作对象的所有成员变量和方法。
由于强引用具有这样的特性,开发人员需要注意在使用强引用时避免造成内存泄漏,即长时间持有不再需要的对象的强引用。如果不再需要某个对象,应该将其引用置为
null
,以使其成为垃圾回收的候选对象,从而及时释放内存资源。 - 生命周期长:强引用的生命周期与其变量的生命周期相同,只有在变量被显式地置为
软引用
-
软引用(Soft Reference)是Java中的一种引用类型,用于描述一些还有用但非必需的对象。当系统内存不足时,垃圾回收器可能会决定回收软引用对象,以释放内存空间。
软引用通过
SoftReference
类来创建,它可以持有对一个对象的引用。例如:Object obj = new Object(); SoftReference<Object> softRef = new SoftReference<>(obj); // 软引用
在上述代码中,
softRef
是对obj
对象的软引用。当内存紧张时,垃圾回收器可能会选择回收softRef
所引用的对象,以释放内存。然而,它只有在系统内存不足时才会进行回收。软引用通常用于实现内存敏感的缓存或高速缓存,以便在内存不足时释放缓存对象,从而保护系统的稳定性。软引用的特点包括:
-
可以被垃圾回收器回收:当系统内存不足时,垃圾回收器可能会决定回收软引用对象。
-
生命周期相对较长:与强引用不同,软引用的生命周期相对较长,即使没有强引用指向对象,软引用仍然存在。
-
对象可直接访问:通过软引用,可以随时访问和操作对象的所有成员变量和方法。
开发人员可以使用软引用来实现缓存、高速缓存或其他需要在内存紧张时释放对象的场景。需要注意的是,软引用的使用需要谨慎,避免过度依赖软引用而导致频繁的垃圾回收,影响系统性能。
-
弱引用
-
弱引用(Weak Reference)是Java中的一种引用类型,用于描述一些非必需的对象。与软引用类似,弱引用在垃圾回收时可以被回收,但其回收的条件更为宽松。
弱引用通过
WeakReference
类来创建,它可以持有对一个对象的引用。例如:
Object obj = new Object();
WeakReference<Object> weakRef = new WeakReference<>(obj); // 弱引用
在上述代码中,weakRef
是对obj
对象的弱引用。当垃圾回收器运行时,无论内存是否紧张,都有可能选择回收weakRef
所引用的对象。弱引用通常用于实现缓存或关联性数据结构,当对象没有强引用时,可以被自动回收,避免占用过多的内存。
弱引用的特点包括:
- 可以被垃圾回收器回收:弱引用的对象在任何时候都有可能被垃圾回收器回收,不仅仅是在内存紧张时。
- 生命周期相对较短:与强引用和软引用不同,弱引用的生命周期相对较短。当没有强引用指向对象时,弱引用可能会被垃圾回收器回收。
- 对象可直接访问:通过弱引用,可以随时访问和操作对象的所有成员变量和方法。
开发人员可以使用弱引用来实现缓存、关联性数据结构或其他不需要长时间持有对象的场景。需要注意的是,由于弱引用的对象随时可能被回收,因此在使用弱引用时需要谨慎处理对象为空的情况,并在必要时重新创建对象。
虚引用
-
虚引用(Phantom Reference)是Java中最弱的引用类型,也是最少被使用的引用类型之一。与其他引用类型不同,虚引用的主要作用不是为了获取对象的引用或跟踪对象的生命周期,而是在对象被垃圾回收时收到一个系统通知。
虚引用通过
PhantomReference
类来创建,它可以持有对一个对象的引用。例如:
Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>(); // 引用队列
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue); // 虚引用
在上述代码中,phantomRef
是对obj
对象的虚引用,并且将引用队列queue
与之关联。当垃圾回收器决定回收obj
对象时,会将phantomRef
放入引用队列queue
中,以便通知应用程序对象已经被回收。
虚引用的特点包括:
-
无法通过虚引用访问对象:虚引用本身不提供对对象的直接访问能力,即无法通过虚引用获取对象的成员变量或方法。
-
用于接收垃圾回收通知:虚引用的主要作用是在对象被垃圾回收时收到一个系统通知。当对象进入Finalization阶段时,虚引用会被放入关联的引用队列中。
-
可以与引用队列一起使用:引用队列允许应用程序获取有关对象回收状态的信息。通过检查引用队列中的虚引用,应用程序可以了解对象是否已被回收。
虚引用的主要应用场景是在对象被回收时进行一些特定的清理操作或记录日志。由于虚引用的使用相对复杂且与垃圾回收机制紧密相关,一般情况下并不常用,仅在某些特殊的需求场景下才会考虑使用。
终结器引用
-
终结器引用(Finalizer Reference)是一种特殊的引用类型,在Java中用于与对象的终结器(Finalizer)方法相关联。终结器引用允许在对象被垃圾回收之前执行终结器方法。
在Java中,每个对象都可以定义一个终结器方法,该方法在对象即将被垃圾回收时被调用。终结器方法通常用于执行对象资源的释放或清理操作,例如关闭文件、释放网络连接等。终结器引用的作用是确保对象在被回收之前能够执行终结器方法。
终结器引用由
java.lang.ref.FinalizerReference
类内部使用,并不直接暴露给开发人员使用。它与对象的终结器方法相关联,当对象被垃圾回收器回收时,终结器引用会在特定的线程中触发终结器方法的执行。需要注意的是,终结器引用的使用在Java中已经被废弃,不推荐使用。这是因为终结器方法的执行具有不确定性和性能问题,可能导致严重的资源泄漏或延迟。取而代之的是,开发人员应该使用显式的资源释放方法(例如
try-with-resources
语句块或finally
块)来确保及时释放对象所持有的资源。终结器引用的存在是为了兼容旧版本的Java代码,但从Java 9开始,已经弃用了终结器引用,并计划在将来的版本中完全移除。因此,开发人员应该避免使用终结器引用,并采用更可靠和可控的资源管理机制。
GcRoot
在Java虚拟机(JVM)中,“GCRoot”(垃圾回收根)是指被视为存活对象的起始点或根节点。垃圾回收器通过追踪从GCRoot开始的引用链,来确定哪些对象是可达的,从而将不可达的对象标记为垃圾并进行回收。
在JVM中,以下几种对象可以被认为是GCRoot:
- 虚拟机栈(Java栈)中的引用:每个线程在执行过程中,会将局部变量、参数和返回值等保存在虚拟机栈中。如果一个对象被局部变量或方法参数引用,它就被视为是GCRoot。
- 方法区中的静态引用:静态变量、常量等在方法区中存储,并且可以被视为GCRoot。
- JNI(Java Native Interface)引用:在Java中调用本地方法时,会与本地代码交互。JNI引用可能会被本地代码持有,因此也被视为是GCRoot。
- 活动线程:正在执行的线程被认为是GCRoot,因为线程对象本身是活动的。
这些GCRoot对象是垃圾回收器扫描和遍历对象图的起点。通过从GCRoot开始,垃圾回收器可以追踪对象之间的引用关系,并标记所有可达对象,将不可达的对象标记为垃圾并进行回收。
GCRoot的概念是JVM中垃圾回收算法的一部分,它确保了不再被引用的对象可以被正确地标记和回收,从而释放内存并维持应用程序的性能和可用性。