Java引用关系(强引用,软引用,弱引用,虚引用)

JAVA虚拟机

在这里插入图片描述
在这里插入图片描述

共享数据区

方法区
  • ClassLoader加载类信息 常量,静态变量 编译后的代码
  • OOM
  • 运行时常量池 字面量public satic final java常量,符号引用 类,接口全名,方法名
java堆
  • 虚拟机能管理的最大的一块内存 GC的主战场
  • OOM
  • 对象实例 数组的内容

线程私有

程序计数器PC
  • 相当于一个执行代码的指示器,用来确认下一行执行的代码的地址
  • 每个线程都有一个
  • 没有OOM的区
虚拟机栈
  • 我们平时说的栈就是这块区域
  • java虚拟机规范中定义了outofmemory和stackoverflow异常
本地方法栈
  • java虚拟机规范中定义了outofmemory和stackoverflow异常
  • 在hotspotVM把虚拟机栈和本地方法栈合为一个栈区

GC垃圾回收器

引用计数算法

Object  o1=new Object(); 计数+1=1
Object  o2;
o2=o1;                 计数+1=2
o1=null;      计数为1    o1和o2都不会回收
  • 缺点:互相引用容易出现计算器永不为0

可达性分析算法

在这里插入图片描述

  • 可作为GC ROOT的对象

  • 虚拟机栈正在运行使用的引用

  • 静态属性 常量

  • JNI引用的对象

  • GC是需要2次扫描才回收对象,所以我们可以用finalize去救活丢失引用的对象

static App a;
@Override
protected void() throws Throwable{
	super.finalize();
	a=this;
}

回收和引用类型的关系

  • 级别和强度:强引用 -> 软引用 -> 弱引用 -> 虚引用
强引用 StrongReference
Object strongReference = new Object();
  • 当内存空间不足时,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
  • 如果强引用对象不使用时,需要弱化从而使GC能够回收,strongReference=null;
  • 显式地设置strongReference对象为null 此时gc认为该对象可被回收,具体回收时间取决于GC算法
  • 如果这个strongReference是全局变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收
  • ArrayList的源码中有这样一段:
 public void clear() {
            modCount++;

            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;

            size = 0;
        }

arrayList类中定义了一个elementData数组,在调用clear方法清空数组时,每个数组元素被赋值为null。
不同于elementData=null,强引用仍然存在,避免在后续调用add()等方法添加元素时进行内存的重新分配。
使用如clear()方法内存数组中存放的引用类型进行内存释放特别适用,这样就可以及时释放内存.

软引用(SoftReference)
  • 如果一个对象只具有软引用,则内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
  • 软引用可用来实现内存敏感的高速缓存。
  • 只有内存不够的时候才会回收,
  • JVM什么时候扫描回收对象是JVM自己的状态决定的,扫描到软引用对象也不一定会回收它,只有内存不够的时候才会回收。
 String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<String>(str);
  • 软引用和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中
 ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);

    str = null;
    // Notify GC 只是通知GC去回收,具体是否回收要看内存和jvm的状态
    System.gc();

    System.out.println(softReference.get()); // abc

    Reference<? extends String> reference = referenceQueue.poll();
    System.out.println(reference); //null

  • 当内存不足时,JVM首先将软引用中的对象引用置为null,然后通知垃圾回收器进行回收
 if(JVM内存不足) {
        // 将软引用中的对象引用置为null
        str = null;
        // 通知垃圾回收器进行回收
        System.gc();
    }
  • 垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软引用对象,而且虚拟机会尽可能优先回收长时间闲置不用的软引用对象。对那些刚构建的或刚使用过的较新的软对象会被虚拟机尽可能保留,这就是引入引用队列ReferenceQueue的原因。

  • 应用:浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从缓存中取

 // 获取浏览器对象进行浏览
    Browser browser = new Browser();
    // 从后台程序加载浏览页面
    BrowserPage page = browser.getPage();
    // 将浏览完毕的页面置为软引用
    SoftReference softReference = new SoftReference(page);

    // 回退或者再次浏览此页面时
    if(softReference.get() != null) {
        // 内存充足,还没有被回收器回收,直接获取缓存
        page = softReference.get();
    } else {
        // 内存不足,软引用的对象已经回收
        page = browser.getPage();
        // 重新构建软引用
        softReference = new SoftReference(page);
    }


弱引用(WeakReference)
  • 具有弱引用的对象拥有比软引用更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
  • JVM首先将软引用中的对象引用置为null,然后通知垃圾回收器进行回收
    @Test
    public void testWeakReference() throws InterruptedException {
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        Object weakObject = new Object();
        //弱引用  把对象加入队列 gc第一次扫到了,就标记下来,第二次扫到直接回收
        WeakReference weakReference = new WeakReference(weakObject,referenceQueue);
       // get() 方法会让弱引用转强引用
        System.out.println("WeakReference:"+weakReference.get());
        System.out.println("referenceQueuee:"+referenceQueue.poll());

        weakObject =null;
        System.gc();
        Thread.sleep(2000);
        System.out.println("WeakReference:"+weakReference.get());
        System.out.println("referenceQueuee:"+referenceQueue.poll());
//        结果 gc回收前可以get到对象 但是poll()为null
//        WeakReference:java.lang.Object@2957fcb0
//        referenceQueuee:null

//        gc之后get不到对象,但是可以poll到对象在内存中创建的信息,当get不到对象的时候说明该对象已经被gc回收
//        WeakReference:null
//        referenceQueuee:java.lang.ref.WeakReference@1376c05c
    }
  • 如果一个对象是偶尔(很少)的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用Weak Reference来记住此对象。
虚引用(PhantomReference)
  • 虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
  • 主要用来跟踪对象被垃圾回收器回收的活动
  • 虚引用与软引用和弱引用的区别
  • 虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
  @Test
    public void testPhantomReference() throws InterruptedException {
        //虚引用:功能,不会影响到对象的生命周期的,
        // 但是能让程序员知道该对象什么时候被 回收了
        // 幽灵 幻影引用   不对生存造成任何影响,用于跟踪GC的回收通知
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        Object phantomObject = new Object();
        PhantomReference phantomReference = new PhantomReference(phantomObject,referenceQueue);
        phantomObject = null;
        System.out.println("phantomObject:"+phantomObject);//null
        System.out.println("phantomReference"+referenceQueue.poll());//null

        System.gc();
        Thread.sleep(2000);
        System.out.println("referenceQueuee:"+referenceQueue.poll());
//        结果:虚引用没有get方法,gc回收前也是poll不到任何信息,
//        phantomObject:null
//        phantomReferencenull

//        gc回收后可以获取到对象存在时的内存信息,可以在此时判断对象已经被回收了
//        referenceQueuee:java.lang.ref.PhantomReference@2957fcb0

    }
引用类型被垃圾回收时间用途生存时间
强引用从来不会对象的一般状态JVM停止运行时终止
软引用当内存不足时对象缓存内存不足时终止
弱引用正常垃圾回收时对象缓存垃圾回收后终
虚引用正常垃圾回收时跟踪对象的垃圾回收垃圾回收后终止
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值