实例池

对于GC类语言,一方面需要依赖垃圾回收器保障内存安全性,周期性暂停世界进行垃圾回收;另一方面为了性能又要尽量避免频繁的对象创建、销毁,以减少世界暂停的时间。

一种避免频繁的对象创建、销毁的方法是使用对象实例池。如下是一个简单的实例池的Kotlin语言实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Pool<T>(private val maxSize: Int, private val createObject: () -> T) {
    private var freeObjects = ArrayList<T>(maxSize)

    fun newObject(): T = if (freeObjects.isEmpty()) createObject()
                         else freeObjects.removeAt(freeObjects.size - 1)

    // REQUIRES: no more external reference towards obj
    // ENSURES: obj can be used by later newObject() call
    fun free(obj: T) {
        if (freeObjects.size < maxSize)
            freeObjects.add(obj)
    }
}

实例池的拥有者通过newObject方法获取实例,通过free方法回收释放实例。实例池的上限大小在初始化时由maxSize参数指定。

当调用newObject()创建对象时

  • 如果池子是空的,说明当前没有可以复用的对象实例,则调用回调函数创建一个新的实例并返回
  • 如果池子非空,说明存在之前创建的对象被池子回收,则将池子最后一个对象返回复用

当调用free()释放实例时,正如注释中说的

  • 外部应当保证不存在其它指向该对象的引用
  • 若池子未被填满,则可以复用

分析完毕,发现maxSize有如下特点:

  • 能够久驻内存的最大池子大小上限,值的选取是一个tradeoff
    • 如果取得太大则可能浪费内存
    • 如果取得太小复用的效果不够好,垃圾回收时延迟较高