文档章节

java那些事(七)之java中使用softReference软引用

thomas1111
 thomas1111
发布于 2014/06/03 22:31
字数 970
阅读 40
收藏 0

使用 Memory Analyzer tool(MAT)分析内存泄漏(一)(以下简称前文)中说到:“Soft Ref(软引用)对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,通过java.lang.ref.SoftReference类实现。”
由于照本宣科,所以我一厢情愿的认为只要Strong Ref不可达,那么GC会自动回收Soft Ref可达的对象。正好最近项目上遇到一个旧版本DWR引起的内存泄漏(新版已修正),由于不愿更新到DWR的最新版本,所以想用Soft Ref来实现。可惜,到最后还是失败了,原因在于没正确使用Soft Ref,那么如何正确使用,在这里聊聊。

由于前文中有提到Weak Ref有个java.util.WeakHashMap实现类,所以就从它的源代码入手吧。WeakHashMap内部是一个Entry[],而Entry是继承了WeakReference并实现Map.Entry接口的静态类,类声明:private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V>。好了,由此可知,Entry实际上是WeakReference的子类,每次实例化Entry也就是在实例化WeakReference,在构造函数中调用super(key, queue)为WeakReference传递标识(key)和ReferenceQueue实例(queue)。ReferenceQueue和WeakReference是联合使用的,作用是当WeakReference所引用的对象被回收后,可以通过WeakReference的poll()来得到WeakReference,但是请注意,如果再对得到的WeakReference进行get(),结果将是null,因为被Weak Ref的对象本身已经被回收。接着再看WeakHashMap的put(K key, V value)方法,该方法又关联调用了私有方法expungeStaleEntries(),expungeStaleEntries()的注释表明,该方法是用来删除失效Entry的,这里调用了ReferenceQueue的poll()方法来找出被回收的对象(已被Weak Ref),然后清除,并缩小键-值映射关系的数目。根据观察,例如remove(Object key)、size()、get(Object key)这些经常使用的方法,内部都优先调用了expungeStaleEntries()。由此可以见,在程序运行中很可能会引起被Weak Ref的对象的回收,所以每次操作都要进行WeakReference的poll(),而后续的清除工作还得手工编码完成。

好,有了WeakHashMap的实现经验,开始实现自己的SoftReference吧。

Pilot类。

/**
 * Pilot class
 * 
@author  rosen jiang
 
*/

package org.rosenjiang.bo;

public class Pilot{
    
private String name;
    
private int age;
    
    
public String getName() {
        
return name;
    }
    
public void setName(String name) {
        
this.name = name;
    }
    
public int getAge() {
        
return age;
    }
    
public void setAge(int age) {
        
this.age = age;
    }
}


SoftRefedPilot类,模拟WeakHashMap的Entry。

/**
 * SoftRefedPilot class
 * 
@author  rosen jiang
 
*/

package org.rosenjiang.bo;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

public class SoftRefedPilot extends SoftReference<Pilot> {
    
public int key;
    
    
public SoftRefedPilot(int key, Pilot referent, ReferenceQueue<Pilot> q) {
        
super(referent, q);
        
this.key = key;
    }
}


测试类TestSoftReference。

/**
 * TestSoftReference class
 * 
@author  rosen jiang
 
*/

package org.rosenjiang.test;

import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
import org.rosenjiang.bo.Pilot;
import org.rosenjiang.bo.SoftRefedPilot;

public class TestSoftReference {

    
public static void main(String[] args) {
        soft();
    }
    
    
static void soft(){
        Map
<Integer, SoftRefedPilot> map = new HashMap<Integer, SoftRefedPilot>();
        ReferenceQueue
<Pilot> queue = new ReferenceQueue<Pilot>();
        
int i = 0;
        
while (i < 10000000) {
            Pilot p 
= new Pilot();
            map.put(i, 
new SoftRefedPilot(i, p, queue));
            
//p = null;
            SoftRefedPilot pollref = (SoftRefedPilot) queue.poll();
            
if (pollref != null) {//找出被软引用回收的对象
                
//以key为标志,从map中移除
                map.remove(pollref.key);
            }
            i
++;
        }
        System.out.println(
"done");
    }
}


好了,在JVM上加入-XX:+PrintGC参数观察GC信息吧。

[GC 55120K->54791K(65088K), 0.0307371 secs]
[GC 58887K->58558K(65088K), 0.0313663 secs]
[Full GC 62654K->52534K(65088K), 0.3171671 secs]
[GC 56630K->56301K(65088K), 0.0278301 secs]
[GC 60397K->60068K(65088K), 0.0303315 secs]
[Full GC 64164K->55894K(65088K), 0.3330122 secs]
[GC 59990K->59660K(65088K), 0.0273494 secs]
[Full GC 63756K->63179K(65088K), 0.3415388 secs]
[Full GC 64640K->43968K(65088K), 0.3204639 secs]
[GC 48064K->47735K(65088K), 0.0329379 secs]


可以看到,当heap达到64m,随即被Full GC,正如前文中说到的那样,内存吃紧的时候,Soft Ref开始进行清理,另外从主观感受和客观日志表明,在Full GC的时候,的确比一般的GC要慢得多,貌似有10倍的差距。所以,利用Soft Ref来做缓存,这个效率还得重新考虑。


© 著作权归作者所有

共有 人打赏支持
thomas1111
粉丝 4
博文 15
码字总数 25972
作品 0
昌平
程序员
有关 SoftReference 的一些事实

Java 的 SoftReference 有很多年都没有被人惦记了。在 Javadoc 里, 它的描述是这样: ”虚拟机在抛出 OutOfMemoryError 之前会保证所有的软引用对象已被清除。此外,没有任何约束保证软引用将...

长源
2013/08/12
0
0
[转]Java 强引用、 软引用、 弱引用、虚引用

1、对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK...

mj4738
2012/07/08
0
2
Java 强引用、 软引用、 弱引用、虚引用

1.对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK...

z.net
2013/09/13
0
1
JAVA中的强引用、弱引用、软引用、虚引用

1.对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK...

向阳而生
2015/11/16
0
0
Java强软弱虚引用Reference

Java强软弱虚引用Reference 本文目的:深入理解Reference 本文定位:学习笔记 学习过程记录,加深理解,提升文字组合表达能力。也希望能给学习Reference的同学一些灵感 源码说明 源码基于jdk...

lichuangnk
06/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

一个可能的NEO链上安全随机数解决方案

0x00 困境 链上安全随机数生成应该算是一个比较蛋疼的问题,哪怕你的系统再牛逼,合约程序困在小小的虚拟机里,哪怕天大的本事也施展不开。 更悲催的是,交易执行的时候,是在每一个节点都执...

暖冰
今天
1
0
【大福利】极客时间专栏返现二维码大汇总

我已经购买了如下专栏,大家通过我的二维码你可以获得一定额度的返现! 然后,再给大家来个福利,只要你通过我的二维码购买,并且关注了【飞鱼说编程】公众号,可以加我微信或者私聊我,我再...

飞鱼说编程
今天
4
0
Spring5对比Spring3.2源码之容器的基本实现

最近看了《Spring源码深度解析》,该书是基于Spring3.2版本的,其中关于第二章容器的基本实现部分,目前spring5的实现方式已有较大改变。 Spring3.2的实现: public void testSimpleLoad(){...

Ilike_Java
今天
1
0
【王阳明心学语录】-001

1.“破山中贼易,破心中贼难。” 2.“夫万事万物之理不外于吾心。” 3.“心即理也。”“心外无理,心外无物,心外无事。” 4.“人心之得其正者即道心;道心之失其正者即人心。” 5.“无...

卯金刀GG
今天
2
0
OSChina 周三乱弹 —— 我们无法成为野兽

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ _刚刚好: 霸王洗发水这波很骚 手机党少年们想听歌,请使劲儿戳(这里) hahahahahahh @嘻酱:居然忘了喝水。 让你喝可乐的话, 你准忘不了...

小小编辑
今天
17
2

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部