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

  1. 2005-07-11 @ Tag 应用技巧   人气:1526
    在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需要回收时,因为没强
    引用关系,它可以随时被回收.

    转载:http://www.cnjbb.org/thread.jsp?boardid=55&threadid=44736&pageno=last#lastpost


感谢易载提供各种支持!
文章分类