自学内容网 自学内容网

Java强软弱虚引用的特点以及应用场景(面试重点)

  • 强:即使OOM也不回收
  • 软:内存溢出前回收
  • 弱:只要垃圾收集就死
  • 虚:对垃圾收集没关系,只有得到通知(插眼,也操作不了对象、只能看到它还活着)
    一、软引用
    代码示例:
public class Softy {
    //-Xms20M -Xmx20M
    public static void main(String[] args) {
        SoftReference<byte[]>sr=new SoftReference<>(new byte[1024*1024*10]);
        System.out.println(sr.get());
        System.gc();
        System.out.println(sr.get());
        SoftReference<byte[]>sr1=new SoftReference<>(new byte[1024*1024*10]);
        System.out.println(sr.get());
        //用作缓存,场景:缓存一张图片进内存,有重要的事情就把它清除,没有就放着
    }
}

使用场景:用作缓存,例如缓存一张图片进内存,有重要的事情就把它清除,没有就放着。

二、弱引用
使用场景:解决threadlocal的内存溢出问题。
1.Threadlocal怎么实现的?
每个线程有一个threadlocalmap对象,向这个map中添加 key:threadlocal对象、value:自己设置的值。不同的线程存数据时是分别向各自的map中存对象,所以threadlocal具有线程隔离性。
向这个map中放的对象是放entry,这个entry继承了弱引用类。在构造方法中entry对key(threadlocal)是被弱引用指向的。
在这里插入图片描述
2.threadlocal的使用场景?
spring声明式事务管理,f1()调用f2()和f3(),必须保证三个方法使用的connection相同,conection对象存放在threadlocal中,保证拿到的是一个链接,在同一个进程中回滚。
3.面试题:为什么弱引用可以防止threadlocal的内存溢出?
key对threadlocal的引用如果用强引用可能会内存泄露。将key(threadlocal)的引用设置成null,如果threadlocal是强引用就会导致上图中的key还在引用着threadlocal对象,不能进行内存回收。但是如果是弱引用就会立刻回收。
回收key后(变成null),去获取value就获取不到了。如果不做处理,依然会内存溢出。所以要调用remove()将整条entry干掉。

public class ThreadTest {
    //容器,线程隔离性
    static ThreadLocal<Person> t=new ThreadLocal<>();
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                Thread.sleep(10);
                t.set(new Person("hxq"));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                Thread.sleep(10);
                System.out.println(t.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        //把entry设置成null
        t.remove();
    }
    static class Person{
        public String name="hxq";
        public Person(String name){
            this.name=name;
        }
    }
}

三、虚引用
在某些情况下引用指向直接内存或者堆外内存,直接内存垃圾回收时,Java垃圾收集器无法管理,用虚引用将对象回收后,放到引用队列中,起到通知垃圾收集器的作用。
场景:

  • NIO包,追踪垃圾回收。reference引用直接内存,直接内存垃圾回收器无法回收。需要用虚引用,做处理。
  • DirectBuffer对象就是引用直接内存
public class Xuy {
    private static final ReferenceQueue<Integer> Queue=new ReferenceQueue<>();
    public static void main(String[] args) {
        //虚引用回收之后放到引用队列里面,虚引用供垃圾回收器特殊处理
        PhantomReference<Integer> phantomReference=new PhantomReference<>(new Integer(1), Queue);
        System.out.println(phantomReference.get());
        //NIO包,追踪垃圾回收。reference引用直接内存,直接内存垃圾回收器无法回收。需要用虚引用,做处理。
        //DirectBuffer对象就是引用直接内存

    }
}

原文地址:https://blog.csdn.net/m0_63803244/article/details/140487284

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!