java四大引用

文章目录

    • 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

  • 结果

    [B@452b3a41
    [B@452b3a41
    null

    当我们手动GC后,软引用对象包裹中的对象还没事,当我们创建一个10M的byte后,最大堆内存不够用了,就将软引用的对象给垃圾回收了。

  • 作用:可以当做缓存,当内存足够的时候可以正常拿到缓存,当内存不够就会先干掉缓存,不至于出现OOM

    import java.lang.ref.SoftReference;
    import java.util.HashMap;
    
    /**
     * SoftRefenceCache
     * @param  key的类型.
     * @param  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();
  • 结果

    虚引用被回收了:java.lang.ref.PhantomReference@5ac42552

第一个线程往集合中放数据,随着数据越来越多,肯定发送GC

第二个线程死循环,从queue中拿数据,如果拿出来的数据不是null那就打印出来

当发生GC的时候,虚引用就会被回收,并且会把回收的同志放到ReferenceQueue中

在NIO中,可以使用虚引用来管理堆外内存

你可能感兴趣的:(所有文章,Java)