Java之"强引用、软引用 和弱引用"

思考:Java中为何会有引用的概念?

思路:在Java里,当一个对象M被创建的时候,它就被放在heap里。当GC运行时,如果发现没有任何引用指向对象M,M就会被回收,用以腾出内存空间。

总结:如果一个对象被回收,需要满足两个条件:

  1. 没有任何引用指向它
  2. 触发GC(Grabage Collection)

众所周知,Java在不主动回收内存方面而优于C、C++等语言所以,有没有什么省心的主动触发GC呢?当然有的--引用。

1、强引用(StrongReference)

定义:强引用是使用最普遍的引用。如果一个对象具有强引用,垃圾回收器绝对不会回收它。

实例代码(1):

public static void main(String[] args){
    Object object=new Book();
    System.gc();
}

运行结果:

<无任何结果>

说明:由于object对象是强引用,即使调用了垃圾回收,也不会回收object。当内存不足时,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,可以通过如下方式来弱化引用:

object=null; //帮助垃圾回收器回收此对象

实例代码(2):

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

说明:在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object对象就会被回收。

注意:如果这个object是个全局变量时,就需要在不使用该对象时置为null,因为强引用不会被垃圾回收。

实例代码(3):回收时将数组中的内容置为null,数组对象为强引用。

private Object[] arr;
public void clear(){
    
    //let gc do the work
    for(int i=0;i<arr.length;i++){
        arr[i]=null;
    }

}

说明:arr数组为强引用,调用清空数组的方法将每个数组内容赋值为null。不同于arr=null,arr的强引用仍然存在,避免在后续调用arr的add()等方法时重新分配内存。但是仍然可以将数组中存放的引用类型清空,及时释放内存。

2、软引用(SoftReference)

理解:如果一个对象只具有软引用,如果内存空间足够,垃圾回收器就不会回收它;如果内存空间不足,就会将这些对象的内存回收。只要它没有被GC,该对象就可以被程序使用。

应用之一:用来实现内存敏感的高速缓存

String value=new String("xxx");//强引用
SoftReference<String> softRefence=new SoftReference<String>(value);//软引用

当内存不足时,可以理解为:

while(JVM.内存不足){
    value=null;    //转为软引用
    System.gc();
}

引用二:浏览器的后退按钮的引用(当按后退按钮时,上一个显示的页面内容是重新进行网路请求还是从缓存中获取?)

1、在当前页面浏览结束时,就进行内存回收,那么下次返回到当前页面就需要重新进行网络请求

2、如果在当前页面浏览结束时,将浏览内容放入内存,会造成大量的内存浪费,甚至会造成内存溢出

那么软引用的好处来了:(当浏览的缓存达到一定的容量,就将对象回收)

Browser bro=new Browser();    //获取的浏览内容对象
SoftReference soft=new SoftReference(bro);//在这之前添加逻辑判断,浏览结束后,就将该对象置为软引用

if(null != soft.get()){
    soft=(Browser)bro.get();//如果没有被GC,直接复用
}else{
    bro=new Browser();    //重新构建,达到了内存复用
    soft=new SoftReference(bro);
}

软引用和引用队列(ReferenceQueue)联合使用的情况:如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中(了解即可)。

3、弱引用

弱引用与软引用的区别:具有弱引用的对象拥有更短的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存控件是否足够,都会回收它的内存。由于垃圾回收线程的优先级很低,因此不一定很快发现具有弱引用的对象。

实例代码:

public static void main(String[] args){
    String value=new String("xxx");
    WeakReference weak=new WeakReferenc(value);
    System.gc();
    }
}

运行结果:

obj [Date:13722379033165] is gc

结果说明:JVM垃圾回收时,弱引用被回收

运行结果等同于:

String value=new String("xxx");
//垃圾回收
if(JVM.垃圾回收){
    value=null;
    System.gc();
}

用例:如果这个对象只是偶尔的使用,而你希望在使用时能够随时获取,但又不影响内存的垃圾回收,那么应该使用WeakReference来标记此对象。

下面的代码会让value再次变成强引用:

String str=weak.get();

4、虚引用

虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。(理解即可)

总结:

Java的四种引用的级别由高到低依次为:

强引用-->软引用-->弱引用-->虚引用

    当垃圾回收器回收时,某些对象会被回收,某些对象不会被回收。垃圾回收器会从根对象Object来标记存活的对象,然后将某些不可达的对象和一些引用的对象进行回收,通过表格说明一下:

      

猜你喜欢

转载自blog.csdn.net/weixin_38664232/article/details/85009499
今日推荐