强引用,软引用,弱引用,虚引用

继承关系图
在这里插入图片描述
强引用
定义:

强引用(系统默认):当内存不足是,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收
最常见的强引用:把一个对象赋给一个引用对象,这个引用对象就是强引用。当一个对象被强引用变量引用时,它是处于可达状态,它是不可能被垃圾回收机制回收的。

在这里插入图片描述
实例:

package com.example.demo.Reference;

import com.example.demo.entity.DateDemo;

/**
 * 强引用类型
 */
public class StrongRederenceDemo {

    public static void main(String[] args) {
        //这样定义默认强引用
        DateDemo dateDemo = new DateDemo();
        //进行引用赋值  dateDemo1 也是强引用
        DateDemo dateDemo1 = dateDemo;
        //进行置空
        dateDemo = null ;
        //手动垃圾回收
        System.gc();
        System.out.println(dateDemo1);
    }
}

显示效果:强引用不会被回收

DateDemo{name='null', date=null}

软引用:
定义:

软引用:是相对于强引用弱一点的引用,需要使用java.lang.ref.SoftReference来实现,内存足够的情况下不会进行垃圾回收,当内存足够的情况下会被回收。

使用场景:
场景一:

软引用通常用在对内存敏感的程序中,比如高速缓存就会用到软引用,内存够用的时候就保留,不够的时候就回收。Mybatis底层用了SoftReference

场景二:

一个应用需要读取大量图片的时候:
 1.每次都从硬盘里面读取信息,可能会严重影响系统性能。
 2.如果一次性全部读取到内存,可能会导致内存的溢出。
 可以使用软引用解决这个问题
 设计思路:
  可以创建一个hashMap来存取图片的URL和相关图片关联的软引用之间的映射关系,内存不足的时候,会自动回收软引用的内存空间,从而有效避免OOM的问题。

在这里插入图片描述
实例:内存够用的情况

package com.example.demo.Reference;

import java.lang.ref.SoftReference;

/**
 * 软引用
 * 内存够用就保留,内存不够就回收
 */
public class SoftReferenceDemo {

    public static void main(String[] args) {
        //object是强引用
        Object object = new Object();
        SoftReference<Object> softReference = new SoftReference<Object>(object);
        //获取软引用对象
        Object softObject = softReference.get();
        System.out.println(object);
        System.out.println(softObject);
        //赋值为null 手动gc
        object = null;
        System.gc();
        System.out.println("=============分割线=======================");
        //查看软引用是否有值
        System.out.println(object);
        System.out.println(softObject);

    }
}

显示效果:软引用对象不会被回收

java.lang.Object@129a8472
java.lang.Object@129a8472
=============分割线=======================
null
java.lang.Object@129a8472

实例二:内存不够,软引用回收,这里的软引用对象为softReference.get()产生的对象,如果给一个引用赋值,就是强引用。

/**
     * 在 Run -> edit configuration 配置jvm参数
     * 通过设置JVM参数设置小的内存空间
     * -Xmx5m -Xms5m -XX:+PrintGCDetails
     */
    private static void NoSpaceRunSoftReference() {
        //object是强引用
        Object object = new Object();
        SoftReference<Object> softReference = new SoftReference<>(object);
        //注意softObject为强引用对象
//        Object softObject = softReference.get();
        //获取软引用对象
        System.out.println(object);
        System.out.println(softReference.get());
        object = null;
        try {
            //创建一个字节数组把内存撑爆
            byte[] bytes = new byte[35 * 1024 * 1024];
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("=============分割线=======================");
            System.out.println("强引用对象:"+object);
            System.out.println("弱引用对象:"+softReference.get());
        }
    }

显示效果:内存不够,软引用被回收

=============分割线=======================
强引用对象:null
弱引用对象:null
Heap
 PSYoungGen      total 1536K, used 68K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
  eden space 1024K, 6% used [0x00000000ffe00000,0x00000000ffe110c0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 4096K, used 1577K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
  object space 4096K, 38% used [0x00000000ffa00000,0x00000000ffb8a408,0x00000000ffe00000)
 Metaspace       used 3577K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 385K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.example.demo.Reference.SoftReferenceDemo.NoSpaceRunSoftReference(SoftReferenceDemo.java:29)
	at com.example.demo.Reference.SoftReferenceDemo.main(SoftReferenceDemo.java:12)

弱引用
定义:

不管JVM内存是否够,只要gc,内存就会被回收。需要使用java.lang.ref.WeakReference来实现,它比软引用的生命周期更短。

适用场景:
大量图片的读取问题,可能会导致性能降低或者OOM的问题
实例一:

package com.example.demo.Reference;

import java.lang.ref.WeakReference;

/**
 * 弱引用
 */
public class WeakReferenceDemo {

    public static void main(String[] args) {
        //创建一个强引用
        Object object = new Object();
        //new弱引用类 来获取弱引用对象
        WeakReference<Object> weakReference = new WeakReference<>(object);
        //先行打印两个对象
        System.out.println(object);
        System.out.println(weakReference.get());
        //手动gc 并且给 object赋值
        object = null;
        System.gc();
        System.out.println("=============分割线================");
        System.out.println(object);
        System.out.println(weakReference.get());
    }
}

展示结果:

java.lang.Object@129a8472
java.lang.Object@129a8472
=============分割线================
null
null

虚引用:
定义:

需要使用java.lang.ref.PlantomReference类来实现。
如果一个对象仅持有虚引用,那么她就和没有引用是一样的,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它来访问对象,需要必须和引用队列(ReferenceQueue)联合使用
gc之后会先放到ReferenceQueue里面

适用场景:

主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。
PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被ac回收,用来实现比finalization机制更灵活的回收操作。

在这里插入图片描述

实例:

package com.example.demo.Reference;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.TimeUnit;

/**
 * 虚引用
 * 使用的是PhantomReference 必须与ReferenceQueue队列一起使用 一般不会使用
 */
public class PhantomReferenceDemo {
    public static void main(String[] args) {
        //创建引用队列
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        Object object = new Object();
        //初始化的时候会把引用队列里面添加到引用类里面
        PhantomReference<Object> phantomReference = new PhantomReference<>(object, referenceQueue);
        System.out.println("object强引用:"+object);
        System.out.println("phantomReference弱引用:"+phantomReference.get());
        System.out.println("referenceQueue队列里面的数据:"+referenceQueue.poll());
        //object 赋值为null
        object = null;
        //手动gc
        System.gc();
        //保证gc完全执行成功
        try {
            TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        //查看gc之后的结果
        System.out.println("===========================================");
        System.out.println("object强引用gc之后:"+object);
        System.out.println("phantomReference弱引用gc之后:"+phantomReference.get());
        System.out.println("referenceQueue队列里面的数据gc之后:"+referenceQueue.poll());
    }
}

显示结果

object强引用:java.lang.Object@129a8472
phantomReference弱引用:null
referenceQueue队列里面的数据:null
===========================================
object强引用gc之后:null
phantomReference弱引用gc之后:null
referenceQueue队列里面的数据gc之后:java.lang.ref.PhantomReference@1b0375b3

课后拓展:WeakHashMap,当gc后,内存全部会被回收

package com.example.demo.Reference;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.WeakHashMap;

/**
 * WeakHashMap的测试
 * 缓存清空,有效避免OOM问题,和保证性能的问题
 * 针对与大量的读取图片的问题
 * 一个应用需要读取大量图片的时候:
 *  1.每次都从硬盘里面读取信息,可能会严重影响系统性能。
 *  2.如果一次性全部读取到内存,可能会导致内存的溢出。可以使用软/弱引用解决这个问题
 */
public class WeakHashMapDemo {
    /**
     * HashMap 当gc后,键值都会被保留
     * WeakHsahMap 当gc后,所有的键值对的内存都会被清空
     * @param args
     */
    public static void main(String[] args) {
        HashMap<Integer, String> hashMap = new HashMap<>();
        Integer key = new Integer(1);
        hashMap.put(key,"添加到hashmap的值");
        //给key赋值为null
        key = null;
        System.out.println("key为null状态下的hashmap:"+hashMap);
        //手动gc
        System.gc();
        System.out.println("gc后key为null状态下的hashmap:"+hashMap);
        System.out.println("================================");
        WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<>();
        Integer weakKey = new Integer(2);
        weakHashMap.put(weakKey,"添加到weakHashMap的值");
        weakHashMap.put(new Integer(3),"弱引用");
        //给weakKey赋值为null
        weakKey = null;
        System.out.println("weakKey为null状态下的weakHashMap的值:"+weakHashMap);
        //手动gc
        System.gc();
        System.out.println("gc后weakKey为null状态下的weakHashMap的值:"+weakHashMap);
    }
}

展示结果:

key为null状态下的hashmap:{1=添加到hashmap的值}
gc后key为null状态下的hashmap:{1=添加到hashmap的值}
================================
weakKey为null状态下的weakHashMap的值:{3=弱引用, 2=添加到weakHashMap的值}
gc后weakKey为null状态下的weakHashMap的值:{}

扩展2:引用队列:gc之后的对象会装入到引用队列里面,在初始化引用类的时候传入相应的引用队列

package com.example.demo.Reference;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

/**
 * 引用队列
 * gc之后的引用对象会添加到引用队列里面
 */
public class ReferenceQueueDemo {
    public static void main(String[] args) {
        //创建引用队列
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        Object object = new Object();
        //初始化的时候会把引用队列里面添加到引用类里面
        WeakReference<Object> objectWeakReference = new WeakReference<>(object, referenceQueue);
        System.out.println("object强引用:"+object);
        System.out.println("objectWeakReference弱引用:"+objectWeakReference.get());
        System.out.println("referenceQueue队列里面的数据:"+referenceQueue.poll());
        //object 赋值为null
        object = null;
        //手动gc
        System.gc();
        //保证gc完全执行成功
        try {TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        //查看gc之后的结果
        System.out.println("===========================================");
        System.out.println("object强引用gc之后:"+object);
        System.out.println("objectWeakReference弱引用gc之后:"+objectWeakReference.get());
        System.out.println("referenceQueue队列里面的数据gc之后:"+referenceQueue.poll());
    }
}

展示结果:

object强引用:java.lang.Object@129a8472
objectWeakReference弱引用:java.lang.Object@129a8472
referenceQueue队列里面的数据:null
===========================================
object强引用gc之后:null
objectWeakReference弱引用gc之后:null
referenceQueue队列里面的数据gc之后:java.lang.ref.WeakReference@1b0375b3

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值