【十一】Java 四种引用总结(强、软、弱、虚)

简介

JVM会在必要时启动垃圾回收,为了方便我们控制对象的生命周期,

从JDK1.2(记错了给我说)开始有四种引用类型,强引用>软引用>弱引用>虚引用。

引用在栈内存中,真实的对象在堆内存中。

栈内存中的东西是某线程独享。

堆内存中的东西是可所有线程共享的。

一、强引用(StrongReference)

一个对象只要有强引用存在,Java GC就不会回收它,无论内存有多紧张,这也是可能发生内存泄漏的一个点。

强引用的声明就是我们最常用的直接new一个对象,比如:

Student s = new Student() 

1.如果上述的Student s = new Student()是在一个方法中定义的,比如方法A。

那么方法A执行完成后,会退出方法栈,该Student的引用就不会存在了, 堆内存中Student的真实对象由于没有了引用,就会被GC回收。

2.如果上述的Student s = new Student()是一个全局变量,用完后需要手动置空。

否则GC不会回收它。 

s = null; 

3.注意当它是集合的时候

List<Student> list = new ArrayList();

ArrayList.clear()方法源码

    public void clear() {
        modCount++;

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

        size = 0;
    }

也就是说调用list.clear()只是把集合内每一个元素设置为=null,这个跟 list=null是不一样了,此时list的强引用还在,为下次add操作做准备,这里只是释放了list中每个元素的引用,并不是释放list本身的引用。

同理在使用map的时候也要注意这个问题,key=null或value=null,跟map本身=null是不一样的。比如ThreadLocalMap的内存泄漏问题。

二、软引用(SoftReference)

如果一个对象只有软引用存在,那么内存空间足够的时候,GC不会回收它。

只有当内存空间不足的时候,GC才会去回收软引用对象。

软引用可以和一个引用队列(ReferenceQueue)联合使用。

软引用可用来实现内存敏感的高速缓存。

声明方式:

SoftReference<Student> s = new SoftReference<>(new Student());

三、弱引用(WeakReference)

一个只具有弱引用的对象,只要垃圾回收的线程发现它,就会回收它,无论内存空间是否足够。

但是垃圾回收线程是一个优先级很低的线程,所以不会很快发现弱引用。

弱引用也可以和一个引用队列(ReferenceQueue)联合使用。

如果一个对象只是偶尔使用,且在要使用的时候又能取到,又不想影响该对象的垃圾回收,那么就可以用弱引用。

声明方式:

WeakReference<Student> s = new WeakReference<>(new Student());

四、虚引用(PhantomReference)

一个只具有虚引用的对象,它就跟没有引用一样,随时可能被GC回收。

虚引用必须和引用队列(ReferenceQueue)联合使用。

引用队列:

如果引用的对象被GC回收,JVM会把这个软引用对象加入到与之相关联的引用队列中去,这样在可触及性发生变化的时候得到“通知”。比如用虚引用做缓存,查看引用队列中是否有目标,在发现JVM要回收它的时候再重新申请内存空间。

虚引用可用来跟踪对象被GC回收的活动。

声明方式及操作引用队列的示例:

package com.sid.reference;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;

/**
 * @program: thread-test
 * @description:
 * @author: Sid
 * @date: 2018-11-26 16:21
 * @since: 1.0
 **/
public class PhantomReferenceTest {
    public static boolean isRun = true;
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Student> referenceQueue = new ReferenceQueue<>();
        new Thread() {
            public void run() {
                while (isRun) {
                    Object obj = referenceQueue.poll();
                    if (obj != null) {
                        try {
                            Field rereferent = Reference.class
                                    .getDeclaredField("referent");
                            rereferent.setAccessible(true);
                            Object result = rereferent.get(obj);
                            System.out.println("gc will collect:"
                                    + result.getClass() + "@"
                                    + result.hashCode() + "\t"
                                    + (Student) result);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();

        Student student = new Student();
        PhantomReference<Student> referent = new PhantomReference<>(student,referenceQueue);

        student = null;
        Thread.currentThread().sleep(3000);
        System.gc();
        Thread.currentThread().sleep(3000);
        isRun = false;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值