泛型对象池
为什么需要用到对象池呢?(C#)
因为实例化一个类需要在内存堆中划出一块内存来让这个对象使用(泛指C#这种有自己的内存管理机制的语言,像C++这种自己管理内存的就不是了),但是这些实例化的对象并不是在整个程序生命周期中都是有用的,当这个对象的工作完成之后它就没用了,那这块内存咋办,会立刻释放吗?不,它会继续保持住这块内存的占用,当内存直到GC去主动释放这块内存。所以在没调用GC的情况下,没实例化一个对象,C#管理的内存堆就会少一块空间,当空间不足的时候会触发GC垃圾回收,然而这个操作是很消耗系统资源的。所以为了减少GC的调用,可以把一些之后可能会再次用到的对象缓存起来,那么当再次需要实例化这个类的对象的时候,就不需要再重新去内存堆里申请新的内存来实例化新的对象了,而因为需要分配到内存少了,所以GC的触发频率也就没这么高了。但是并不是说所有的东西都适合对象池,因为还被引用着的对象所占用着的内存是不会被GC回收的,所以如果滥用对象池会导致内存堆里的内存被占用着一直不释放导致“内存泄漏”。
实现对象池(非泛型)
public class FreeableObj
{
public int Val { get; private set; }
public FreeableObj() { }
public void SetVal(int val)
{
Val = val;
}
public void Free()
{
Val = 0;
}
}
public class ObjectPool
{
private Stack<FreeableObj> objectPool = new Stack<FreeableObj>();
public void Reserve(int reserveNum)
{
while (objectPool.Count < reserveNum)
{
objectPool.Push(new FreeableObj());
}
}
public FreeableObj GetObject()
{
if (objectPool.Count <= 0)
return new FreeableObj();
return objectPool.Pop();
}
public void FreeObject(FreeableObj obj)
{
obj.Free();
objectPool.Push(obj);
}
}
实现对象池(泛型)
当如果有很多类都需要用到对象池的时候,如果每个类都要重新去写一次对象池会很麻烦,所以可以用泛型来写一个通用的对象池模型,为了让对象池缓存的对象确保有Free方法,可以规定对象池缓存的对象都要实现IFreeable接口。
public interface IFreeable
{
void Free();
}
public class ObjectPoolGeneric<T> where T : IFreeable, new()
{
private Stack<T> objectPool = new Stack<T>();
public void Reserve(int reserveNum)
{
while (objectPool.Count < reserveNum)
{
objectPool.Push(new T());
}
}
public T GetObject()
{
if (objectPool.Count <= 0)
return new T();
return objectPool.Pop();
}
public void FreeObject(T obj)
{
obj.Free();
objectPool.Push(obj);
}
}