java四大引用
java四大引用
java有四种引用类型:强引用、软引用、弱引用、虚引用
四大引用设计作用
因为java的内存分配和内存回收,都是由JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,即可达性分析
- 设计目的:
- 可以让程序员通过代码的方式来决定某个对象的生命周期
- 有利用垃圾回收
强引用
使用最广泛的
Object o = new Object();
只要某个对象有强引用与之关联,这个对象就永远不会被回收,即使内存不足,JVM也只会抛出OOM也不回去回收。
直到强引用和对象之间的关联被中断,就可以被回收了。
中断关联
n=null;
可以手动调用GC,看看强引用和对象之间的关联被中断,资源会不会被回收。
public class Student {
@Override
protected void finalize()throws Throwable{
System.out.println(" Student 被回收了");
}
public static void main(String[] args) {
Student student = new Student();
System.gc();
System.out.println("===============");
student = null;
System.gc();
}
}
- 结果:
Student 被回收了
- 开发中不要重写finalize方法
- 开发中可以将一些对象手动赋值为NULL,可以提醒JVM将这些资源进行垃圾回收
软引用
-
创建一个软引用
SoftReference<Student> studentSoftReference = new SoftReference<Student>(new Student());
-
软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获取包裹的对象,只要get一下就可以。
SoftReference<Student> studentSoftReference = new SoftReference<Student>(new Student()); Student student = studentSoftReference.get(); System.out.println(student);
-
特点:
- 当内存不足时,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给干点
- 也就是只有在内存不足,JVM才会回收该对象
-
验证:
SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]); System.out.println(softReference.get()); System.gc();; System.out.println(softReference.get()); byte[] bytes = new byte[1024*1024*10]; System.out.println(softReference.get());
-
运行时需要加上JVM参数:-Xmx20M 代表最大的堆内存为20M
-
结果
当我们手动GC后,软引用对象包裹中的对象还没事,当我们创建一个10M的byte后,最大堆内存不够用了,就将软引用的对象给垃圾回收了。
-
作用:可以当做缓存,当内存足够的时候可以正常拿到缓存,当内存不够就会先干掉缓存,不至于出现OOM
import java.lang.ref.SoftReference; import java.util.HashMap; /** * SoftRefenceCache * @param <K> key的类型. * @param <V> value的类型. */ public class SoftReferenceCache<K, V> { private final HashMap<K, SoftReference<V>> mCache; public SoftReferenceCache() { mCache = new HashMap<K, SoftReference<V>>(); } /** * 将对象放进缓存中,这个对象可以在GC发生时被回收 * * @param key key的值. * @param value value的值型. */ public void put(K key, V value) { mCache.put(key, new SoftReference<V>(value)); } /** * 从缓存中获取value * * @param key * * @return 如果找到的话返回value,如果被回收或者压根儿没有就返* 回null */ public V get(K key) { V value = null; SoftReference<V> reference = mCache.get(key); if (reference != null) { value = reference.get(); } return value; } public static void main(String[] args) { SoftReferenceCache<Integer, String> mPersonCache = new SoftReferenceCache<Integer, String>(); mPersonCache.put(0, ("zhong")); mPersonCache.put(1, ("hu")); // 去拿zhong String p = (String) mPersonCache.get(1); } }
弱引用
弱引用和软引用类似,只是关键字换成了WeakReferce
WeakReference weakReference = new WeakReference<byte[]>(new byte[1024*1024*10]);
System.out.println(weakReference.get());
- 特点:不管内存是否够用,只要发生GC就会被回收
- 用途:ThreadLocal、WeakHashMap。
虚引用
虚引用又称为幻影引用
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1],queue);
System.out.println(reference.get());
-
虚引用的使用和其他的还是有较大的区别。
-
结果:
null
-
因为其get方法直接返回了null
-
创建虚引用对象,我们除了把包裹的对象传了进去,还传了一个ReferenceQueue(队列)
-
虚引用必须与ReferenceQueue一起使用,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。
ReferenceQueue queue = new ReferenceQueue();
List<byte[]> bytes = new ArrayList<>();
PhantomReference<Student> reference = new PhantomReference<Student>(new Student(),queue);
new Thread(() -> {
for (int i = 0; i < 100;i++ ) {
bytes.add(new byte[1024 * 1024]);
}
}).start();
new Thread(() -> {
while (true) {
Reference poll = queue.poll();
if (poll != null) {
System.out.println("虚引用被回收了:" + poll);
}
}
}).start();
Scanner scanner = new Scanner(System.in);
scanner.hasNext();
-
结果
虚引用被回收了:[email protected]
第一个线程往集合中放数据,随着数据越来越多,肯定发送GC
第二个线程死循环,从queue中拿数据,如果拿出来的数据不是null那就打印出来
当发生GC的时候,虚引用就会被回收,并且会把回收的同志放到ReferenceQueue中
在NIO中,可以使用虚引用来管理堆外内存