在程序里面经常会遇到的一个问题是短时间内创建大量的对象,导致内存紧张,从而触发GC导致性能问题。对于这个问题,我们可以使用对象池技术来解决它。通常对象池中的对象可能是bitmaps,views,paints等等。关于对象池的操作原理,不展开述说了,请看下面的图示:
使用对象池技术有很多好处,它可以避免内存抖动,提升性能,但是在使用的时候有一些内容是需要特别注意的。通常情况下,初始化的对象池里面都是空白的,当使用某个对象的时候先去对象池查询是否存在,如果不存在则创建这个对象然后加入对象池,但是我们也可以在程序刚启动的时候就事先为对象池填充一些即将要使用到的数据,这样可以在需要使用到这些对象的时候提供更快的首次加载速度,这种行为就叫做预分配。使用对象池也有不好的一面,程序员需要手动管理这些对象的分配与释放,所以我们需要慎重地使用这项技术,避免发生对象的内存泄漏。为了确保所有的对象能够正确被释放,我们需要保证加入对象池的对象和其他外部对象没有互相引用的关系。
工作中需要减少对一些比较耗系统资源对象的创建和初始化工作,因此想到了apache commons-pool工具包。commons-pool包里主要包括三个重要的接口:
ObjectPool用于管理要被池化的对象的借出和归还;
ObjectPoolFactory用于大量生成相同类型和设置的ObjectPool。
看看下面的例子
一个Connection类,可以想象成一个远程连接比如数据库连接等。其中包括创建连接,关闭连接,和一个print方法。
最后是一个测试类
运行测试类,可以看到在第一个循环里虽然循环了10次,一共要了10个MyConnection对象,但是每次返回的都是“conn_1”这个MyConnection对象实例,并且从日志可以看出,makeObject方法只被调用了一次,因此,除了第一次以外,后面的每次申请都是从pool里取出来的。而在第二个循环中,每次申请了两个MyConnection对象实例,从日志可以看到,在第二个循环里也只调用了一次makeObject方法,并且创建的是conn_2对象实例,这是由于conn_1这个对象已经在第一个循环中被创建了出来,此时只是直接拿出来使用了。这里为了好测试,没有在第二个循环中做异常处理,真实情况下应该像第一个循环里的代码类是,在borrowObject和使用pool中对象出现异常时要记得调用invalidateObject方法,并且归还pool中的对象。