转:Java对象的强、软、弱和虚引用(五)

4.使用弱引用构建非敏感数据的缓存

4.1全局 Map 造成的内存泄漏

无意识对象保留最常见的原因是使用Map将元数据与临时对象(transient object)相关联。假定一个对象具有中等生命周期,比分配它的那个方法调用的生命周期长,但是比应用程序的生命周期短,如客户机的套接字连接。需要将一些元数据与这个套接字关联,如生成连接的用户的标识。在创建Socket时是不知道这些信息的,并且不能将数据添加到Socket对象上,因为不能控制 Socket 类或者它的子类。这时,典型的方法就是在一个全局 Map 中存储这些信息,如下面的 SocketManager 类所示:使用一个全局 Map 将元数据关联到一个对象。

1.            public class SocketManager {  

2.                private Map<SOCKET,&NBSP;USER> m = new HashMap<SOCKET,&NBSP;USER>();  

3.               

4.                public void setUser(Socket s, User u) {  

5.                   m.put(s, u);  

6.                }  

7.               

8.                public User getUser(Socket s) {  

9.                   return m.get(s);  

10.            }  

11.           

12.            public void removeUser(Socket s) {  

13.               m.remove(s);  

14.            }  

15.        }  

这种方法的问题是元数据的生命周期需要与套接字的生命周期挂钩,但是除非准确地知道什么时候程序不再需要这个套接字,并记住从 Map 中删除相应的映射,否则,Socket User 对象将会永远留在 Map 中,远远超过响应了请求和关闭套接字的时间。这会阻止 Socket User 对象被垃圾收集,即使应用程序不会再使用它们。这些对象留下来不受控制,很容易造成程序在长时间运行后内存爆满。除了最简单的情况,在几乎所有情况下找出什么时候 Socket 不再被程序使用是一件很烦人和容易出错的任务,需要人工对内存进行管理。

4.2如何使用WeakHashMap

Java集合中有一种特殊的Map类型—WeakHashMap,在这种Map中存放了键对象的弱引用,当一个键对象被垃圾回收器回收时,那么相应的值对象的引用会从Map中删除。WeakHashMap能够节约存储空间,可用来缓存那些非必须存在的数据。关于Map接口的一般用法。

下面示例中MapCache类的main()方法创建了一个WeakHashMap对象,它存放了一组Key对象的弱引用,此外main()方法还创建了一个数组对象,它存放了部分Key对象的强引用。

1.            import java.util.WeakHashMap;  

2.               

3.            class Element {  

4.                private String ident;  

5.               

6.                public Element(String id) {  

7.                   ident = id;  

8.                }  

9.               

10.            public String toString() {  

11.               return ident;  

12.            }  

13.           

14.            public int hashCode() {  

15.               return ident.hashCode();  

16.            }  

17.           

18.            public boolean equals(Object obj) {  

19.               return obj instanceof Element && ident.equals(((Element) obj).ident);  

20.            }  

21.              

22.            protected void finalize(){  

23.               System.out.println("Finalizing "+getClass().getSimpleName()+" "+ident);  

24.            }  

25.        }  

26.           

27.        class Key extends Element{  

28.            public Key(String id){  

29.               super(id);  

30.            }  

31.        }  

32.           

33.        class Value extends Element{  

34.            public Value (String id){  

35.               super(id);  

36.            }  

37.        }  

38.           

39.        public class CanonicalMapping {  

40.            public static void main(String[] args){  

41.               int size=1000;  

42.               Key[] keys=new Key[size];  

43.               WeakHashMap map=new WeakHashMap();  

44.               for(int i=0;i< SPAN>

45.                   Key k=new Key(Integer.toString(i));  

46.                   Value v=new Value(Integer.toString(i));  

47.                   if(i%3==0)  

48.                      keys[i]=k;  

49.                   map.put(k, v);  

50.               }  

51.               System.gc();  

52.            }  

53.        }  

从打印结果可以看出,当执行System.gc()方法后,垃圾回收器只会回收那些仅仅持有弱引用的Key对象。id可以被3整除的Key对象持有强引用,因此不会被回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值