1.强引用
强引用就是我们平时使用最多的那种引用,就比如以下的代码
//创建一个对象
Object obj = new Object();//强引用
这个例子就是创建了一个对象并建立了强引用,强引用一般就是默认支持的当内存不足的时候,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会回收对象。即使在解除对对象的强引用后,只要系统内存充足,垃圾回收器不会立即回收对象。强引用使得对象在被引用时一直保持有效,直到引用被显式解除。
以下三种引用就是比较不常见的了,这三种引用虽然叫引用但是和我们理解的那种栈上的变量指向堆上的对象的指针不是一回事。
千万不要将软弱虚这三种引用理解为那种栈上的变量指向堆上的对象的指针。
软引用、弱引用、虚引用:这三种引用其实就是一个个的类,通过对应的类名翻译过来的中文名称。
// 软引用
public class SoftReference<T> extends Reference<T> {
}
// 弱引用
public class WeakReference<T> extends Reference<T> {
}
// 虚引用
public class PhantomReference<T> extends Reference<T> {
}
2.软引用
发生了垃圾回收,并且回收后内存仍然不足,并且被软引用指向的对象没有强引用,那么被软引用指向的对象就会被回收。
public class SoftReferenceDemo {
public static void main(String[] args) {
Object a = new Object();
SoftReference softReference = new SoftReference<>(a);//软引用
//a和软引用指向同一个对象
System.out.println(a);//java.lang.Object@4554617c
System.out.println(softReference.get());//java.lang.Object@4554617c
//内存够用,软引用不会被回收
a = null;
System.gc();//内存够用不会自动gc,手动唤醒gc
System.out.println(a);//null
System.out.println(softReference.get());//java.lang.Object@4554617c
//内存不够用时
try{
//配置Xms和Xmx为5MB
byte[] bytes = new byte[1024102430];//设置30MB超内存
}catch (Throwable e){
e.printStackTrace();
}finally {
System.out.println(a);//null
System.out.println(softReference.get());//null
}
}
}
第一步
第二步撤了对a对象的强引用只剩软引用了,手动唤醒gc对象被清除了
3.弱引用
弱引用(Weak Reference)是Java中一种比强引用更弱的引用类型。当一个对象只被弱引用关联时,在下一次垃圾回收时,该对象就有可能被回收。垃圾回收器会在适当的时候回收仅被弱引用持有的对象,即使内存并不紧张。
public class WeakReferenceDemo {
public static void main(String[] args) {
// 创建一个对象并建立弱引用
Object obj = new Object();
WeakReference<Object> weakRef = new WeakReference<>(obj);
// 对象仍然存在,可以正常使用
System.out.println("Object is still accessible: " + weakRef.get());
// 解除对对象的强引用
obj = null;
// 手动触发垃圾回收
System.gc();
// 垃圾回收后,对象被回收,弱引用返回null
System.out.println("Object after garbage collection: " + weakRef.get());
}
}
- 软引用和弱引用一般都可以被用于实现内存敏感的缓存
- ThreadLocalMap中的entry实体就是一个弱引用
static class ThreadLocalMap {
// Entry是一个弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
为什么要在ThreadLocal中使用弱引用?
先简单说一下在 ThreadLocal 的实现中,它使用了一个名为 ThreadLocalMap 的哈希表来存储每个线程的局部变量。这个 ThreadLocalMap 的键(Key)是 ThreadLocal 对象的弱引用,而值(Value)则是与线程相关联的实际对象。
1.防止内存泄露:使用弱引用允许 JVM 在内存紧张时回收 ThreadLocal 对象,而不必等待整个ThreadLocalMap 被显式清理。这种灵活性有助于更好地管理内存,特别是在高负载或长时间运行的应用程序中。
2.灵活的内存管理:使用弱引用允许 JVM 在内存紧张时回收 ThreadLocal 对象,而不必等待整个 ThreadLocalMap 被显式清理。这种灵活性有助于更好地管理内存,特别是在高负载或长时间运行的应用程序中。
4.虚引用
虚引用(Phantom Reference)是Java中最弱的引用类型之一,无法通过引用直接获取到对象实例。虚引用主要用于跟踪对象被垃圾回收的状态。当一个对象只被虚引用关联时,其实际上并不影响对象的生命周期,也就是说,垃圾回收器随时可能回收被虚引用关联的对象,我们甚至无法通过get方法获取到对象实例。