什么是对象池 
Unity中调用UnityEngine.Object.Instantiate函数进行对象复制是开销较大(相对)的做法,每帧如果只会创建几个对象那完全不用在意性能万一一个对象特别复杂可能还是要在意一下 。但如果在一帧中,创建了上百甚至上千个对象(比如说生成一大堆弹幕),这一帧肯定会卡顿。可以使用对象池来缓解这个问题 
对象池会包含许多已经初始化完毕的对象,我们可以从池中获取已创建好的对象,或者将使用完毕的对象返还到池中。 
一般开发中,像Socket连接,线程才会用到对象池,因为创建这样的对象开销非常大。中小型对象就别用了,CLR内存分配速度几乎可以忽略不计,小对象的GC问题也可以通过struct来缓解。所以这里就不写通用对象池了,因为用不到(大概)。 
 
实践 
简易对象池 
一个最最最简易的GameObject对象池可以这样写 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public  class  ObjectPool  {     private  readonly  Queue<GameObject> _queue;     private  readonly  GameObject _prefab;     public  ObjectPool (GameObject prefab, int  initCount = 0  )     {         _queue = new  Queue<GameObject>(initCount);         _prefab = prefab;         for  (var  i = 0 ; i < initCount; i++)         {             Recycle(Allocate());         }     }     public  GameObject Get ()     {         var  result = _queue.Count == 0  ? Allocate() : _queue.Dequeue();         result.SetActive(true );         return  result;     }     public  void  Recycle (GameObject instance )     {         instance.SetActive(false );         _queue.Enqueue(instance);     }     private  GameObject Allocate ()  { UnityEngine.Object.Instantiate(_prefab); } }
 
其实就是封装了下队列和实例化对象的方法。但这样写有很多问题,先不说内存泄漏,就这个回收时没有任何检查,谁知道我返还回来的对象,是不是从这个池中实例化出来的呢?(能保证返还回来的一定是正确的话当我没说)
优化 
为了解决脑抽返还了不是这个对象池实例化出来的对象,第一时间想到可以使用HashSet来记录对象,每次回收时检查一下。尽管HashSet的查询时间已经是O(1)级别了,但比起直接访问数组索引还是慢了那么点,有没有只使用数组办法呢。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public  class  ObjectPool  {     private  readonly  GameObject _template;     private  readonly  List<GameObject> _pool;     private  readonly  Stack<int > _usable;     public  IReadOnlyList<GameObject> Container => _pool;     public  ObjectPool (GameObject template, int  initCount )     {         _template = template;         _pool = new  List<GameObject>(initCount);         _usable = new  Stack<int >(initCount);         for  (var  i = 0 ; i < initCount; i++)         {             var  go = Instantiate();             var  ptr = _pool.Count;             _pool.Add(go);             Return(ptr);         }     }     private  GameObject Instantiate ()  { return  UnityEngine.Object.Instantiate(_template); }     public  int  Get ()     {         int  ptr;         GameObject go;         if  (_usable.Count <= 0 )         {             go = Instantiate();             ptr = _pool.Count;             _pool.Add(go);         }         else          {             ptr = _usable.Pop();             go = _pool[ptr];         }         go.SetActive(true );         return  ptr;     }     public  void  Return (int  ptr )     {         if  (ptr >= _pool.Count) throw  new  ArgumentException();         _usable.Push(ptr);         var  go = _pool[ptr];         go.SetActive(false );     }                                         }
 
由于对象创建完毕后放入数组,几乎不会再有变动,因此我们可以用数组储存对象,用一个栈来储存未被使用过的对象在数组中的下标。获取对象时从栈中弹出一个下标,需要访问对应的对象也可以通过Container属性加下标的形式。
简单,粗暴,有效(个人没出过问题)。当然这个只适合知道最多会创建多少个对象的时候,因为没有阈值可能会导致内存爆满的问题。 
TODO:对象池爆满的问题