Unity 对象池

为什么要对象池?

不用时时刻刻用到就去创建,不用到时销毁物体。用一个池子,将对象管理起来,分为活动的和非活动的。活动的即为在使用的,非活动的当前只在池子当中,外部不使用。

对象池的功能:能够避免对多次重复使用的对象重复实例化,造成内存碎片,GC(系统垃圾回收)过多的发生,而系统垃圾回收很消耗CPU,造成游戏顿卡,影响体验

好处:保证帧率基本稳定
坏处:会使内存略微增加

老外写的池子:Object Pooling – A Great way to Increase Performance

分析:老外写的这个池子将某一种物体的一种池子相互独立开,用一个“池子管理器”去管理所有的对象池。但是,有个地方有问题,在ObjectPool类中Shrink(…)方法将大于初始池子的对象list回归为初始大小时,存在内存泄露,只是将某一个物体的引用从list里面Remove,但是却没有将这个引用指向的物体销毁。这样会导致,这个物体的引用丢失,物体本身占据的内存却无法释放,造成内存泄露。

改进下:

//********************************************************************
// 文件名: ObjectPoolMgr.cs
// 描述: 对象池
// 作者: 李伟
// 创建时间: 2015-07-18
//
//********************************************************************


using SK;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ObjectPoolMgr : Singleton<ObjectPoolMgr>, IMgr
{
    public void Init() {}

    public void Reset() {}


    /*==================================================================================*/


    private Dictionary<String, ObjectPool> _objectPools;

    public ObjectPoolMgr()
    {
        _objectPools = new Dictionary<string, ObjectPool>();
    }


    public bool IsContainPool(string poolName)
    {
        return _objectPools.ContainsKey(poolName);
    }


    public void CreatePool(string poolName, PoolGameObject obj, int initialPoolSize, int maxPoolSize, bool canClear)
    {
        var pool = new ObjectPool(poolName, obj, initialPoolSize, maxPoolSize, canClear);
        _objectPools.Add(poolName, pool);
    }


    public PoolGameObject GetObject(string poolName)
    {
        if (!IsContainPool(poolName)) return null;

        return _objectPools[poolName].GetObject();
    }


    public void Destroy(string poolName, PoolGameObject obj)
    {
        if (!IsContainPool(poolName))
        {
            GameObject.DestroyObject(obj);
        }

        _objectPools[poolName].BackToUnUsedObjList(obj);
    }


}


public class ObjectPool
{
    private List<PoolGameObject> _usedObjList = new List<PoolGameObject>();
    private List<PoolGameObject> _unUsedObjList = new List<PoolGameObject>();

    private string _poolName;
    private PoolGameObject _pooledObj;

    private int _initialPoolSize;
    private int _maxPoolSize;

    private GameObject _poolObjsParent;

    public int TotalCount { get { return totalCount(); } }


    public ObjectPool(string poolName, PoolGameObject obj, int initialPoolSize, int maxPoolSize, bool canClear)
    {
        _poolName = poolName;
        _pooledObj = obj;

        _poolObjsParent = new GameObject(string.Format("{0}_{1}", _poolName, "pool"));
        GameObject.DontDestroyOnLoad(_poolObjsParent);

        for (int i = 0; i < initialPoolSize; i++)
        {
            var ObjTemp = GameObject.Instantiate(_pooledObj, Vector3.zero, Quaternion.identity) as PoolGameObject;
            ObjTemp.SetObjectPool(this);
            ObjTemp.transform.parent = _poolObjsParent.transform;

            _unUsedObjList.Add(ObjTemp);

            GameObject.DontDestroyOnLoad(ObjTemp);
        }

        _maxPoolSize = maxPoolSize;
        _initialPoolSize = initialPoolSize;

        if (canClear)
        {
            EventMgr.Self.ObjPoolEvents.AddClearPoolEventListener(clearPool);
        }
    }


    public PoolGameObject GetObject()
    {
        for (int i = _unUsedObjList.Count - 1; i >= 0; i--)
        {
            var obj = _unUsedObjList[i];

            if (_unUsedObjList[i] == null)
            { 
                _unUsedObjList.Remove(obj);

                continue;
            }

            _usedObjList.Add(obj);
            _unUsedObjList.Remove(obj);

            return obj;
        }

        if (totalCount() < _maxPoolSize)
        {
            var obj = GameObject.Instantiate(_pooledObj, Vector3.zero, Quaternion.identity) as PoolGameObject;
            obj.SetObjectPool(this);
            obj.transform.parent = _poolObjsParent.transform;

            _usedObjList.Add(obj);

            return obj;
        }

        D.Error("pool _maxPoolSize");

        return null;
    }


    public void BackToUnUsedObjList(PoolGameObject obj)
    {
        if (obj == null) return;

        if (totalCount() <= _maxPoolSize && _usedObjList.Contains(obj))
        {
            obj.transform.parent = _poolObjsParent.transform;

            _unUsedObjList.Add(obj);
            _usedObjList.Remove(obj);
        }
        else
        {
            GameObject.Destroy(obj);
        }
    }


    private void clearPool()
    {
        int objectsToRemoveCount = totalCount() - _initialPoolSize;
        if (objectsToRemoveCount <= 0)
        {
            return;
        }

        for (int i = _unUsedObjList.Count - 1; i >= 0; i--)
        {
            var obj = _unUsedObjList[i];
            _unUsedObjList.Remove(obj);

            GameObject.Destroy(obj);
        }
    }


    public void RemoveEventListener()
    {
        EventMgr.Self.ObjPoolEvents.AddClearPoolEventListener(clearPool);
    }


    private int totalCount()
    {
        return _usedObjList.Count + _unUsedObjList.Count; 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值