老调重弹之Java引用类型

一直知道Java的引用分四类:强引用、软引用、弱引用、虚引用,但仔细想想又觉得领悟不够多,故此总结一下;
首先要分清两个概念,对象可达性、不同类别的引用;
对象可达性针对对象的概念,不同的引用针对引用的概念;
虽然下文描述显示可达性再是引用类型,但实际系统允许时,判断一个对象能否回收,首先要看到它的可达性,如何判断它的可达性,肯定是先判断指向它的那些“引用”;
所以分析时,应该先是看某对象的各个引用,它们的类别,再近而结合对象本身的可达性;

对象达到性

当Java虚拟机(JVM)觉得内存不够用的时候,会触发垃圾回收操作(GC),清除无用的对象,释放内存。
可是如何判断一个对象是否是垃圾呢?
其中的一个方法是计算指向该对象的引用数量。
如果引用数量为0,那么该对象就为垃圾(Thread对象是例外),否则还有用处,不能被回收。但是如果把引用数为0的对象都回收了,还是不能满足内存需求怎么办?Java把引用分为4种类型,垃圾回收器会尝试回收只有弱引用的对象。

达到性性分析算法

在主流的商用程序语言(Java、C#,甚至包括前面提到的古老的Lisp)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。
这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点。
从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
如图3-1所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。

这里写图片描述

Java语言中,可作为GC Roots的对象包括下面几种:

虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。

强可达性对象

在一个线程内,不需要其他引用对象,直接使用,一般新创建的对象针对创建它的线程来说都是强可达的;
任何强可达对象,在它的线程内都不会被回收;
只有它变为不可达对象,才会被回收

软可达对象

当系统内存不足时,系统保证会回收软可达对象;
软引用可用来实现内存敏感的高速缓存.但是具体的行为还是得依赖于JVM。并且多少跟内存回收机制有关,保障很少并且跟具体的JVM发行版本有关。为了缓存的可靠(及其他更多特性),大多数人都会选用像Ehcache而不是用软引用实现自己的缓存。但在一些场合,使用软引用确实可以让代码非常优雅、简洁。

弱可达对象

在垃圾回收期进行垃圾回收时,不管·内存情况,都会回收此类对象;
弱引用不能阻止垃圾回收机制清理他指向的引用。弱引用最常见的使用情景是通过WeakHashMap。它是一种简单地将对象的生命周期跟Map中对象的索引域(key)绑定的方式。只有当WeakHashMap中的Key是强可达,也就是WeakHashMap中的数据域(Data域)的对象,在应用程序的其他地方有别的引用的时候,它里面的值才不会被回收。一旦应用程序中没有其他对WeakHashMap中对象的引用,那么它的所有的key就会变成弱可达,不需要用户的额外干预,所有WeakHashMap中的对象都会被清除。这是一种优雅地防止内存泄露的方式。

虚引用对象

如果一个对象既没有强可达性,也没有软可达性、弱可达性,他已经被终结(finalized),并且有一些虚引用(phantom reference)指向它,那么它就具有虚可达性。

不可达

当一个对象不能通过以上的方式指向,那么这个对象就变得不可达,并因此适合被回收。

4种Java引用

强引用(StrongReference)
我们平时申明变量使用的就是强引用,普通系统99%以上都是强引用。比如,String s = "Hello World"

软引用(SoftReference)
类似弱引用,只不过Java虚拟机会尽量让软引用的存活时间长一些,迫不得已才清理。

弱引用(WeakReference)
垃圾回收器某个时刻决定回收软可达的对象的时候,会清理软引用,并可选的把引用存放到一个引用队列(ReferenceQueue)。

虚引用(PhantomReference)
仅用来处理资源的清理问题,比Object里面的finalize机制更灵活。get方法返回的永远是null,Java虚拟机不负责清理虚引用,但是它会把虚引用放到引用队列里面。

例子

使用HashMap,会报out of memory错误。
public static void main(String[] args) {
        Map<String, String> list = new HashMap<String, String>();
        long i = 1;
        while (i < 100000000L) {
            list.put(
                    String.valueOf(i),
                    "JDJJDJJJJJJJJJJ%%%%%%%%JJJJJJJJJJJJJJJKKKKKKKKKKKKKKKKKJJJJJJ"
                            + "JJJKKKKKHDDDJDJDJDJDJDJDJDJJDJDJDJDJDJDJJDJDJDJDJJDJDJJJJJJJJJ"
                            + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ"
                            + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJ");

            // 测试第一个是否依然存活
            if (i % 100000 == 0) {
                System.out.println(list.get(String.valueOf(1)));
            }

            i++;
        }
    }
public static void main(String[] args) {
        Map<String, String> list = new WeakHashMap<String, String>();
        long i = 1;
        while (i < 100000000L) {
            list.put(
                    String.valueOf(i),
                    "JDJJDJJJJJJJJJJ%%%%%%%%JJJJJJJJJJJJJJJKKKKKKKKKKKKKKKKKJJJJJJ"
                            + "JJJKKKKKHDDDJDJDJDJDJDJDJDJJDJDJDJDJDJDJJDJDJDJDJJDJDJJJJJJJJJ"
                            + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ"
                            + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJ");

            // 测试第一个是否依然存活
            if (i % 100000 == 0) {
                System.out.println(list.get(String.valueOf(1)));
            }

            i++;
        }
    }

猜你喜欢

转载自blog.csdn.net/fengshenju2018/article/details/49678713
今日推荐