大对象缓存的实现与调用原则

来源:互联网 发布:怎样免费装修淘宝店铺 编辑:程序博客网 时间:2024/05/14 12:09
在UOP之数据缓存一文中我介绍了对象缓存的一般原则,对其中的大对象缓存只是简单
介绍了基本原理.本文详细地说明如何进行大对象缓存.

基于本栏目的类型,在本栏目中讨论的内容是如何恰当地应用某种技术来进行系统设计.
而不会介绍某种基本技术.如本文涉及的对象的次(软)/弱/虚引用的概念,这是你要自己
参看相关资料而掌握的.


大对象(Fat Object)是指在创建时要耗费一定时间,或创建完成后要占用一定的空间的对
象,简单说,就是"来之不易"啊.比如图形对象,Socket连结等.所以这类对象不宜频繁地创
建.应该尽量使用它的缓冲.对象的缓冲不仅仅指缓存对象本身,而且包括多次复用.

但因为这样的对象占用了较大的空间,如果使用频度不高又不能长时间放在内存中,所以在
持久与创建之间产生一个矛盾.既不能每次调都重新创建,又不能一次创建后就永久保持.

算了,这么烦的事,费那么多脑子干什么.交给JVM自己决定好了.
把大对象缓存原则交给JVM自己决定,理由是:

如果JVM发生资源回收,说明现在空间吃紧,那么这类大对象就应该腾出空间了.而平时,JVM
没有发生资源回收,说明还有一定的空间冗余,那就尽量让这样的大对象活得久一些.减少
重复创建的机率.

要达到上面的条件,就是不能有强引用,如果有强引用持有这样的大对象,那么无论如果JVM
大需要回收资源的时候不会回收这个对象.


所以,我们创建一个大对象后,要么就一直不持有这个对象的强引用,要么在强引用后要立即
将对象和引用之间的关联打断.

SoftReference sr = null;//声明一个用于存返回对象的指示.

if(sr==null || sr.get()==null){
    sr = new SoftReference(new FatObject());
}

我们每次都可以从sr.get()获取这个大对象,只要sr.get()为null,说明原来那个对象已经
被回收了,下次调用时就要重新生成.


这样生成的对象,如果我们将它赋给了强引用句柄,如:

Image img = (Image)sr.get();
那么在调用img引用完成后,一定要img = null;才能打断引用句柄img与那个大对象的关联.
否则,在JVM进行GC时,它就不能被回收,一直占着资源不能释放.而这样的编程方式又不符合
常归的编程习惯,比竟,JAVA是自动回收内存的,不象C/C++的程序员在使用对象后会记得手工
清除对象,要让JAVA程序员每次使用完对象后都要手动执行handler = null;这样的语句实在
不是一回事.

其实,C#的属性是一个非常好的方式,虽然Class.Attribute象是引用一个类的字段,而实际上
是调用了getXXX方法.在java中我们只好这样来引用缓存的大对象,虽然仍然不是最常规的习
惯,但比每次调用后都要handler = null;这样要自然得多了:

class CacahedFatImage{
    SoftReference sr = null;
    String filePath;
    public CacahedFatImage(String filePath){
        this.filePath = filePath;
        sr = new SoftReference(new Image(filepath));
    }
    
    public Image getObject(){
        if(sr==null || sr.get()==null)
            sr = new SoftReference(new Image(filepath));
        return (Image)sr.get();
    }

}


在调用的时候,先生成CacahedFatImage对象:

CacahedFatImage cfi = new CacahedFatImage();
以后在调用这个大对象的时候都以cfi.getObject()来代替img引用.

如:cfi.getObject().getWidth();
   cfi.getObject().getHeight();


这样,只要这个对象没有被回收我们就可以随时获取到它,而如果JVM需要回收时,因为没强
引用关系,它可以随时被回收.

原创粉丝点击