对象池
1. 使用情景
- 当需要频繁地创建和销毁对象时;
- 对象的大小一致时;
- 在堆上进行对象内存分配十分缓慢或者会导致内存碎片;
- 每个对象都封装了像数据库或者网络连接这样很昂贵又可以重用的资源,如数据库、网络的连接;
2.注意点
- 可能在闲置对象上浪费内存;
- 同时激活的对象数量是固定的,如果超出容量有几种做法:
- 在固定场景下调整对象池的大小,完全阻止这一点;
- 不创建对象
- 强行清理现存对象
- 增加对象池的大小;如果这么做了,当这些额外空间不再被占用时,必须考虑是否恢复到原容量。
- 每个对象的内存大小是固定的;
- 如果对象大小不一时,将浪费内存。即每个槽都需要能存储最大的对象。
- 重用对象不会被自动清理,可能保留了另一个同类型对象的信息。
- 未使用的对象会保留在内存内
- 潜在的问题:如果对象池中的对象在回收时,对象仍然保留任何对其他对象的引用,也会阻止垃圾回收器回收它。
3.空闲表
- 使用数组作为池子容器时,如果不想浪费时间在查找空闲粒子上,需要保留一个指向未使用对象的指针列表。或者采用空闲表,通过联合体的特性,将空闲对象的内存做成一个指针列表。
4. 对象与对象池是否耦合
- 耦合的情况,在对象中保存一个“是否使用”的标志位
- 不耦合的情况,在对象池中单独空出一块数组,保留每个对象的使用情况
5.谁来初始化重用对象
- 假如在对象池内部初始化重用对象
- 对象可以完全封装它管理的对象;可以将对象完全置于对象池内部;
- 对象池与对象如何被初始化密切相关。对象池必须支持所有的对象初始化函数;
- 假如对象在外部被初始化
- 对象池只需要简单返回新对象的引用即可;
- 要处理新对象创建失败的情况
遗留问题
- 工程里对象池都是用list stack作为容器,而不是数组;并且不在一开始分配池子空间,而是在回收时将对象加入容器;
- 这里存在内存碎片的可能性,C#语言的GC机制是否能一定程度上防止碎片呢?