首页 > 学院 > 开发设计 > 正文

Reference-持有引用简析

2019-11-08 20:04:46
字体:
来源:转载
供稿:网友

Reference是java.lang.ref包中的抽象类,主要作用为了包装引用,为垃圾回收提供更大的灵活性,继承Reference的类中有三个非常具有代表性,分别是SoftReference、WeakReference、PhantomReference。分别对应java虚拟机规范中的软,弱、虚三种引用,可能我们平时用的比较少,大多数情况下,我们是直接new对象进行赋值,这属于强引用,垃圾回收器并不会进行回收。 下面通过例子,它们分别如何应用,首先我们将设置jvm参数(eclipse中设置,不会的百度):-XX:+PRintGCDetails -XX:+PrintGCTimeStamps -Xms10m -Xmx10m。

public class SimpleJava{ static class Entry { public final int id; public final String type; public Entry(int id, String type) { this.id = id; this.type = type; } public final byte[] b = new byte[1024 * 1024 * 1]; @Override protected void finalize() throws Throwable { checkqueue(); System.out.println("对象最后回收前标记:" + this); } @Override public String toString() { return "id : " + id + ", type : " + type; } } private static void checkqueue() { Reference<? extends Entry> r = rq.poll(); if(r != null) { System.out.println("对象进入回收队列:" + r.get()); checkqueue(); } } private static ReferenceQueue<Entry> rq = new ReferenceQueue<>(); public static void main(String[] args) { int size = 10; LinkedList<Reference<Entry>> list = new LinkedList<>(); for(int i = 0; i < size; i++) {// list.add(new WeakReference<>(new Entry(i, "Weak"), rq)); list.add(new SoftReference<>(new Entry(i, "soft"), rq));// list.add(new PhantomReference<>(new Entry(i, "Phantom"), rq)); System.out.println("元素:--" + list.getLast().get()); } }}

我们通过SoftReference对对象进行包装,然后加入到list集合中,此时每个子项SoftReference就是属于强引用,垃圾回收器并不会回收。 现在我们观看打印结果。

元素:--id : 0, type : soft0.080: [GC [PSYoungGen: 1800K->488K(3072K)] 1800K->1656K(10240K), 0.0016371 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--id : 1, type : soft元素:--id : 2, type : soft0.082: [GC [PSYoungGen: 2674K->488K(3072K)] 3842K->3736K(10240K), 0.0015083 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--id : 3, type : soft元素:--id : 4, type : soft0.084: [GC [PSYoungGen: 2559K->504K(3072K)] 5807K->5816K(10240K), 0.0013574 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.086: [Full GC [PSYoungGen: 504K->0K(3072K)] [ParOldGen: 5312K->5660K(7168K)] 5816K->5660K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0108456 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 元素:--id : 5, type : soft元素:--id : 6, type : soft0.097: [Full GC [PSYoungGen: 2063K->1024K(3072K)] [ParOldGen: 5660K->6684K(7168K)] 7723K->7708K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0066311 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 元素:--id : 7, type : soft0.104: [Full GC [PSYoungGen: 2058K->2048K(3072K)] [ParOldGen: 6684K->6684K(7168K)] 8742K->8732K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0045077 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.108: [Full GC [PSYoungGen: 2048K->2048K(3072K)] [ParOldGen: 6684K->6673K(7168K)] 8732K->8721K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0075998 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 对象进入回收队列:nullException in thread "main" 对象进入回收队列:null对象进入回收队列:null对象进入回收队列:null对象进入回收队列:null对象进入回收队列:null对象进入回收队列:null对象进入回收队列:null对象最后回收前标记:id : 1, type : soft对象最后回收前标记:id : 0, type : soft对象最后回收前标记:id : 3, type : soft对象最后回收前标记:id : 2, type : soft对象最后回收前标记:id : 5, type : soft对象最后回收前标记:id : 4, type : soft对象最后回收前标记:id : 7, type : soft对象最后回收前标记:id : 6, type : softjava.lang.OutOfMemoryError: Java heap space at com.esy.rice.tool.simple.SimpleJava$Entry.<init>(SimpleJava.java:21) at com.esy.rice.tool.simple.SimpleJava.main(SimpleJava.java:48)

当最后堆内存不足时,系统进行gc,但任然不能进行内存的回收,此时finalize方法进行执行,并且在引用队列中有Reference对象,但是其中包装的对象却不能取出。这是怎么一回事呢? 先简单描述下垃圾回收的几个阶段,首先是对象判活,进行对象可达性分析,之后将不可达的对象进行F-Queue中,然后调用对象的finalize方法,此时对象最后能够自救的方法(需要this指向方法外的引用),最后gc才会将确定不可达的对象进行回收。 从上面的打印中可以看出,ReferenceQueue正是Reference包装的对象进行回收的队列,打印的信息同样也印证了垃圾回收的几个过程,但是上面我们都是强调gc会回收不可达的对象。我们程序中并没有不可达的对象啊,似乎都是强引用。而这就是SoftReference的特性,由其进行包装的类,当内存即将溢出的时候,gc会进行回收动作,我们程序中报错是因为gc是需要时间的,这个时间比内存分配慢了些。 从SoftReference这个特性我们可以看出,SoftReference非常适合内存敏感的高速缓存。 当我们把程序中new SoftReference<>(new Entry(i, “soft”), rq)进行注释,换成new WeakReference<>(new Entry(i, “Weak”), rq)。 看下面打印:

元素:--id : 0, type : Weak0.077: [GC [PSYoungGen: 1800K->504K(3072K)] 1800K->1640K(10240K), 0.0018023 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--id : 1, type : Weak元素:--id : 2, type : Weak对象进入回收队列:null0.080: [GC [PSYoungGen: 2690K->504K(3072K)] 3826K->3740K(10240K), 0.0021215 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--id : 3, type : Weak对象最后回收前标记:id : 0, type : Weak元素:--id : 4, type : Weak0.083: [GC [PSYoungGen: 2601K->504K(3072K)] 5838K->5820K(10240K), 0.0017948 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.085: [Full GC [PSYoungGen: 504K->0K(3072K)] [ParOldGen: 5316K->4636K(7168K)] 5820K->4636K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0095411 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 对象进入回收队列:null对象进入回收队列:null元素:--id : 5, type : Weak对象进入回收队列:null元素:--id : 6, type : Weak0.095: [GC [PSYoungGen: 2081K->128K(3072K)] 6718K->6812K(10240K), 0.0016162 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 0.097: [Full GC [PSYoungGen: 128K->0K(3072K)] [ParOldGen: 6684K->6685K(7168K)] 6812K->6685K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0094562 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 对象进入回收队列:null元素:--id : 7, type : Weak对象进入回收队列:null对象进入回收队列:null元素:--id : 8, type : Weak0.107: [Full GC [PSYoungGen: 2069K->2048K(3072K)] [ParOldGen: 6685K->6685K(7168K)] 8755K->8733K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0039976 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.111: [Full GC [PSYoungGen: 2048K->2048K(3072K)] [ParOldGen: 6685K->6674K(7168K)] 8733K->8722K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0086574 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 对象最后回收前标记:id : 2, type : Weak对象进入回收队列:null对象进入回收队列:null对象最后回收前标记:id : 8, type : Weak对象最后回收前标记:id : 7, type : WeakException in thread "main" 对象最后回收前标记:id : 6, type : Weak对象最后回收前标记:id : 5, type : Weak对象最后回收前标记:id : 4, type : Weak对象最后回收前标记:id : 3, type : Weak对象最后回收前标记:id : 1, type : Weakjava.lang.OutOfMemoryError: Java heap space at com.esy.rice.tool.simple.SimpleJava$Entry.<init>(SimpleJava.java:21) at com.esy.rice.tool.simple.SimpleJava.main(SimpleJava.java:47)

发现和SoftReference引用有些相同,都响应垃圾回收,然而回收的时间点,却有些区别,这正是弱引用的特性,在每一次垃圾回收的时候,都会进行弱引用的清除。 最后我们把weakReference进行注释,让new PhantomReference<>(new Entry(i, “Phantom”), rq)加入list中,运行程序:

元素:--null0.081: [GC [PSYoungGen: 1800K->488K(3072K)] 1800K->1640K(10240K), 0.0015818 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--null元素:--null0.083: [GC [PSYoungGen: 2623K->496K(3072K)] 3775K->3760K(10240K), 0.0014629 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 元素:--null对象最后回收前标记:id : 2, type : Phantom对象最后回收前标记:id : 1, type : Phantom元素:--null对象最后回收前标记:id : 0, type : Phantom0.085: [GC [PSYoungGen: 2619K->504K(3072K)] 5883K->5832K(10240K), 0.0017430 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.087: [Full GC [PSYoungGen: 504K->0K(3072K)] [ParOldGen: 5328K->5660K(7168K)] 5832K->5660K(10240K) [PSPermGen: 2497K->2496K(21504K)], 0.0114532 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 元素:--null对象进入回收队列:null元素:--null0.099: [Full GC [PSYoungGen: 2089K->1024K(3072K)] [ParOldGen: 5660K->6683K(7168K)] 7749K->7708K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0082086 secs] [Times: user=0.08 sys=0.02, real=0.01 secs] 对象进入回收队列:null元素:--null0.108: [Full GC [PSYoungGen: 2076K->2048K(3072K)] [ParOldGen: 6683K->6683K(7168K)] 8760K->8732K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0042951 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.112: [Full GC [PSYoungGen: 2048K->2048K(3072K)] [ParOldGen: 6683K->6673K(7168K)] 8732K->8721K(10240K) [PSPermGen: 2496K->2496K(21504K)], 0.0085989 secs] [Times: user=0.09 sys=0.01, real=0.01 secs] 对象进入回收队列:null对象最后回收前标记:id : 3, type : Phantom对象最后回收前标记:id : 7, type : PhantomException in thread "main" 对象最后回收前标记:id : 6, type : Phantom对象最后回收前标记:id : 5, type : Phantom对象最后回收前标记:id : 4, type : Phantomjava.lang.OutOfMemoryError: Java heap space at com.esy.rice.tool.simple.SimpleJava$Entry.<init>(SimpleJava.java:21) at com.esy.rice.tool.simple.SimpleJava.main(SimpleJava.java:49)

可以看出,PhantomReference进行包装的对象,不管有没有gc都不能进行取出,仔细观察还可以看到,finalize进行打印时,有时候队列中没有别回收的对象,这正是PhantomReference的特性,也是唯一的作用,被其引用的对象在遇到垃圾回收时,会进行通知,也就是finalize的调用。


上一篇:文章标题

下一篇:数据结构队列

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表