欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java四大引用

程序员文章站 2022-04-30 09:09:16
...

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

  • 结果

    [[email protected]
    [[email protected]
    null

    当我们手动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();

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

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

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

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

相关标签: 所有文章 Java