【java基础】强引用、软引用、弱引用、虚引用

11 篇文章 0 订阅

jdk1.2之前,每个对象在堆中都有一个引用计数属性,引用新增1次则计数加1,引用每释放一次则计数减一,判断对象是否可以回收的条件是对象是否可达状态;如果可达则表示对象不可回收,如果不可达就是可以回收状态;
jdk1.2之后,为了更好的控制堆中对象的生命周期,将对象分成了强引用、软引用、弱引用以及虚引用。

一、概念

1、强引用: 垃圾回收器绝对不会回收强引用,即使内存不足,宁愿抛出outOfMemoryError;
Object object = new Object();
除非主动将对象设置为null(全局参数的过程中),或者该对象超出看该对象的生命周期(方法中对象,如下:),才可以使垃圾回收器回收该对象;

public void test(){
Object object = new Object();

}
首先对象的引用在方法栈中,而该对象引用的内容在堆中,当退出方法栈,对象无引用,从而GC回收,但是当该对象是全局参数就需要主动将对象设置为null。

2、软引用: 当对象是软引用时,内存充足的情况下是不会回收该对象,但当内存不足会主动回收软引用对象,释放内存;
用来缓存,当内存不足会自动回收释放;
使用场景:可以将一些访问频繁的数据放在软引用中,直到内存不足的情况下重新从数据库中获取;

3、弱引用: 当对象为弱引用时,当垃圾回收器收集对象的时候会回收弱引用对象;
和软引用的区别在于:软引用在内存不足的情况才会回收,但弱引用对象在垃圾回收的时候就会被回收。
使用场景:其中ThreadLocal源码中就使用了弱引用,就是为了防止线程积累过多而导致内存不足,
其中ThreadLocal存储数据是为了保证每个线程都是独立的一个数据副本,从而可以在当前线程任何地方获取, 不需要通过方法参数传来传去,但是ThreadLocal不能解决父子线程数据之间的传递,每个线程数据都是独立的副本,但有时候需要在子线程中获取父线程的变量值,那么InheritableThreadLocal类就是为了解决父类线程数据副本传递到子线程的过程,是引用传递,子线程引用的值改变,父线程引用的值也改变,但是InheritableThreadLocal在线程池中不能将父线程数据传递到子线程,是因为线程池获取线程过程中不是主动new Thread线程,new Thread的过程中会将父线程副本传递给对应的子线程,线程池获取线程不一样,是一堆已经创建好的线程中获取,但有时候需要根据父线程的副本传递给线程池中某个子线程,那么阿里巴巴开发的TransmittableThreadLocal类就很好的解决了线程池父子线程副本数据的传递。
在这里插入图片描述

4、虚引用: 在任何时候都会被垃圾回收器回收。
在这里插入图片描述

二、代码

@Data
public class Role {

    private String name = "role";
    /**
     * 弱:WeakReference.java,每次GC都会被回收;
     */
    public static void weakReference() {
        Role role = new Role();

        WeakReference<Role> roleWeakReference = new WeakReference<>(new Role());

        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(role==null){
            System.out.println("强引用对象role已经被回收!");
        }
        if(roleWeakReference.get()  == null){
            System.out.println("弱引用对象roleWeakReference 已经被回收!");
        }
    } /**
     * 软引用:softReference.java,每次GC都会被回收;
     */
    public static void softReference() {
        Role role = new Role();

        SoftReference<Role> softReference = new SoftReference<>(new Role());

        System.gc();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(role==null){
            System.out.println("强引用对象role已经被回收!");
        }

        if(softReference.get()  == null){
            System.out.println("软引用对象roleWeakReference 已经被回收!");
        }else{
            System.out.println("软引用对象值还存在:"+softReference.get());
        }
    }


    /**
     * 注:软引用和弱引用的区别是:软引用是需要等内存不够才回收,system.gc只是起到通知垃圾回收的作用,
     * 而且当JVM垃圾回收器在内存不足的情况下回收软引用对象时,会根据引用队列的顺序先回收老对象;
     * 而弱引用system.gc通知后,会安排回收
     * @param args
     */
    public static void main(String[] args) {

//        weakReference();
//
//        /**
//         * 弱引用 队列使用
//         */
//        weakReferenceQueue();
//
//        System.out.println("=============================================");
//
//
//        softReference();
//        /**
//         * 软引用队列使用
//         */
//        softReferenceQueue();
//
//
        System.out.println("=============================================");

        /**
         * 虚引用队列,虚引用必须和引用队列使用;
         */
        phantomReferenceQueue();
    }


    private static void phantomReferenceQueue () {

        ReferenceQueue<Role> reference = new ReferenceQueue();
        PhantomReference<Role> phantomReference = new PhantomReference<>(new Role(),reference);
        Reference<? extends Role> poll = reference.poll();
        if(poll !=null){
            System.out.println("gc回收之前引用队列有值");
        }
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Reference<? extends Role> poll2 = reference.poll();
        if(poll2 !=null){
            System.out.println("gc回收之后引用队列有值");
        }

        if(phantomReference.get()  == null){
            System.out.println("虚引用对象phantomReference已经被回收!");
        }
    }



    private static void softReferenceQueue() {
        Role role = new Role();

        ReferenceQueue<Role> reference = new ReferenceQueue();

        SoftReference<Role> roleSoftReference = new SoftReference<>(new Role(),reference);
        Reference<? extends Role> poll = reference.poll();
        if(poll !=null){
            System.out.println("gc回收之前引用队列有值");
        }
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Reference<? extends Role> poll2 = reference.poll();
        if(poll2 !=null){
            System.out.println("gc回收之后引用队列有值");
        }
        if(role==null){
            System.out.println("强引用对象role已经被回收!");
        }
        if(roleSoftReference.get()  == null){
            System.out.println("软引用对象roleSoftReference已经被回收!");
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值