深入理解JVM虚拟机:JAVA引用类型

《深入理解Java虚拟机》 专栏收录该内容
5 篇文章 1 订阅

深入理解JVM虚拟机之:JAVA引用类型

引用类型可以说是整个Java开发的灵魂所在,如果没有合理的引用操作,那么就有可能产生垃圾问题,但是对于引用也需要有一些合理化的设计。在很多的时候并不是所有的对象都需要被我们一直使用,那么就需要对引用的问题做进一步的思考。从JDK1.2之后关于引用提出了四种方案: 

  • 强引用:当内存不足的时候,JVM宁可出现OutOfMemory错误停止,也需要进行保存,并且不会将此空间回收; 
  • 软引用:当内存不足的时候,进行对象的回收处理,往往用于高速缓存中; 
  • 弱引用:不管内存是否紧张,只要由垃圾产生了,那么立即回收; 
  • 幽灵引用:和没有引用是一样的。

1. 强引用

强引用是JVM默认的支持模式,即:在引用的期间内,如果该堆内存被指定的栈内存有联系,那么该对象就无法被GC所回收,而一旦出现了内存空间不足,就会出现“OutOfMemoryError”错误信息。 
范例:观察强引用。

package cn.test.demo;
public class TestDemo{
    public static void main(String[]args){
        Object obj=new Object();//强引用,默认的支持
        Object ref=obj;//引用传递
        obj=null;//断开了一个连接
        System.gc();
        System.out.println(ref);
    }
}

如果此时堆内存有一个栈内存指向,那么该对象将无法被GC回收。 
强引用是我们一直在使用的模式,并且也是以后开发之中主要的使用模式,正因为强引用具备这样的内存分配异常问题,所以,尽量少实例化对象。

2. 软引用

在许多的开源组件之中,往往会使用软引用作为缓存组件出现,其最大的特点在于:不足时回收,充足时不回收。想实现软引用,则需要有一个单独的类来实现控制:java.lang.ref.SoftReference。这个类的方法如下: 

  • 构造:public SoftReference(T referent) 
  • 取出数据:public T get() 

范例:观察软引用

package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
    public static void main(String[]args){
        Object obj=new Object();
        SoftReference<Object> ref=new SoftReference<Object><obj>;//软引用
        obj=null;//断开连接
        System.gc();
        System.out.println(ref.get());
    }
}

如果此时内存空间充足,那么对象将不会回收,如果空间不充足,则会进行回收。

package cn.test.demo;
import java.lang.ref.SoftReference;

public class TestDemo{
    public static void main(String[]args){
        Object obj=new Object();
        String str="hello";
        obj=null;//断开连接
        SoftReference<Object> ref=new SoftReference<Object><obj>;//软引用
        try{
            for(int x=0;x<Inter.MAX_VALUE;x++){
                str+=str+x;
                str.intern();
            }
        }catch(Throwable e){

        }
                   System.out.println(ref.get()+"##############################");
    }
}

3.弱引用

弱引用本质的含义指的是说只要一进行GC处理,那么所引用的对象将会被立刻回收。弱引用需要使用的是Map接口的子类:

java.util.WeakHashMap。 

范例:观察弱引用

package cn.test.demo;
import java.lang.ref.SoftReference;

public class TestDemo{
    public static void main(String[]args){
        String key=new String(“hi”);
        String value=new String(“hello”);
        Map<String,String> map=new WeakHashMap<String,String>();
        map.put(key,value);
        System.out.println(map.get(key));
        key=null;
        System.out.println(map);
        System.gc();
        System.out.println(map);
    }
}  

一旦出现GC,则必须进行回收处理,而且一回收一个准。 
HashMap与WeakHashMap区别? 
HashMap是强引用,而WeakHashMap是弱引用。

在java.lang.ref包中存在有一个WeakReference的一个子类。 
范例:观察WeakReference

package cn.test.demo;
import java.lang.ref.SoftReference;

public class TestDemo{
    public static void main(String[]args){
        String key=new String(“hi”);
        WeakReference<String> map=new WeakHashMap<String>(key);
        Key=null;
        System.out.println(ref.get());
        System.gc();
        System.out.println(ref.get());
    }
}

弱引用之所以不敢轻易使用的原因,就是因为其本身一旦有了GC之后就会立刻清空,这个对于程序的开发不利。

4. 引用队列

所谓的引用队列就是保存那些准备被回收的对象。很多的时候所有的对象的回收扫描都是从根对象开始的。 
那么对于整个GC而言,如果要想确定那些对象可以被回收,就必须确定好引用的强度,这个也就是所谓的引用路径的设置。 

如果现在要找到对象5,那么很明显1找到5属于“强”+“软”,而2找到5属于“强”+“弱”。软引用要比弱引用保存的强,所以这个时候实际上对于对象的引用而言,如果要进行引用的关联判断,那么就必须找到强关联,那么为了避免非强引用对象所带来的内存引用问题,所以提供有一个引用队列的概念,如果在创建软引用或者弱引用类型的时候使用了引用队列的方式,则这个对象被回收之后会自动保存在引用队列之中。

范例:使用引用队列

package cn.test.demo;
import java.lang.ref.SoftReference;

public class TestDemo{
    public static void main(String[]args)throws Exception{
    Object obj=new Object();
    ReferenceQueue<Object> queue=new ReferenceQueue<>();
    WeakReference<Obeject> ref=new WeakReference<Object>(obj,queue);
    System.out.println(queue.poll());
    obj=null;
    System.gc();
    Tread.sleep(200);    //延迟200毫秒
    System.out.println(queue.poll());  
}
}

这种引用队列主要是做一些被回收对象的控制,意义不大,了解即可。

5. 幽灵引用(虚引用)

永远取得不了的数据就叫做幽灵引用。 
范例:观察幽灵引用

package cn.test.demo;
import java.lang.ref.SoftReference;

public class TestDemo{
    public static void main(String[]args) throws Exception{
        Object obj=new Object();
        ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
        PhantomReference<Object> ref=new PhantomReference<Object>(obj,queue);
        System.gc();
        System.out.println(ref.get());
        System.out.println(queue.poll());
    }
}

所有保存在幽灵引用类型中的数据都不会真正的保留。

 

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值