1: Purpose
Memory management is an important item in software development. In the game, there are some objects that need to be created and destroyed frequently, such as bullets in shooting games, obstacles in parkour games, etc. the usual method is to use instance and Destroy to continuously open up and release memory, but such operation is fatal and will produce memory fragments
What is memory fragmentation: memory fragmentation means that the free space in the heap is broken into many small memory fragments instead of large contiguous memory blocks. The total available memory may be large, but the longest contiguous space may be small
For example, as shown in the figure below, suppose we have 20 spare bytes in the end, but it is divided into two parts by a piece of memory O2 in use. At this time, we will fail to allocate 15 bytes of objects, which will eventually lead to the crash of the game
So we can define a pool object, which contains a set of reusable objects
When a new object is needed, ask for one from the pool. If there is no such object in the pool, just Instantiate one. If there is such an object in the pool, SetActive=true directly
When destruction is needed, do not use Destroy, directly set active = false and put it back into the pool
In this way, objects can be easily created and destroyed without allocating memory or other resources
2: Problems solved and advantages
——Avoid game crashes caused by memory fragmentation caused by allocating memory and freeing memory
3: Use
——Put all preform files under the subfolder of Prefabs folder under Resources folder
——The script of each object pool object inherits the ReusableObj class, implements OnSpawn and onunspown methods, and overrides the Reset method
——Use objectpoolmgr Ins. XXX
ObjectPoolMgr.Ins.Allocate("Effect"); ObjectPoolMgr.Ins.Recycle(gameObject);
4: Code implementation
using System.Collections.Generic; using UnityEngine; /// <summary> ///Object pool manager /// </summary> public class ObjectPoolMgr : Singleton<ObjectPoolMgr> { public const string ResDir = "Prefabs/";//Resource directory private Dictionary<string, SubPool> poolCache = new Dictionary<string, SubPool>();//All the pools #region Main /// <summary> ///Allocate resources /// </summary> public GameObject Allocate(string resName) { if (!poolCache.ContainsKey(resName)) { if (!CreatePool(resName)) { Debug.LogError("Failed to create pool:" + resName); return null; } } return poolCache[resName].Allocate(); } /// <summary> ///Recycling resources /// </summary> public void Recycle(GameObject obj) { string poolName = obj.GetComponent<ReuseableObj>().HostPoolId; poolCache[poolName].Recycle(obj); } #endregion /// <summary> ///Create pool /// </summary> private bool CreatePool(string resName) { string path = ResDir + resName; GameObject prefab = Resources.Load<GameObject>(path); if (prefab == null) { return false; } SubPool subPool = new SubPool(resName, prefab); poolCache.Add(resName, subPool); return true; } } /// <summary> ///Zichizi /// </summary> public class SubPool { public string poolId;//Pool name public GameObject prefab;//Preform public Stack<GameObject> unUsedObjCache = new Stack<GameObject>();//All unused objects in the pool /// <summary> ///Initialize pool /// </summary> public SubPool(string poolId, GameObject prefab) { this.poolId = poolId; this.prefab = prefab; } /// <summary> ///Allocate resources /// </summary> public GameObject Allocate() { GameObject obj = GetUnusedObj(); if (obj == null) { obj = SpawnObj(); } obj.GetComponent<ReuseableObj>().OnSpawn(); obj.SetActive(true); return obj; } /// <summary> ///Recycling resources /// </summary> public void Recycle(GameObject obj) { obj.SetActive(false); unUsedObjCache.Push(obj); obj.GetComponent<ReuseableObj>().OnUnSpawn(); obj.GetComponent<ReuseableObj>().Reset(); } /// <summary> ///Generate object /// </summary> public GameObject SpawnObj() { GameObject obj = Object.Instantiate(prefab); obj.GetComponent<ReuseableObj>().HostPoolId = poolId; return obj; } /// <summary> ///Get an unused object from the pool /// </summary> private GameObject GetUnusedObj() { GameObject obj = null; if (unUsedObjCache.Count <= 0) return null; obj = unUsedObjCache.Pop(); return obj; } }
using UnityEngine; /// <summary> ///Objects reused by object pool /// </summary> public abstract class ReuseableObj : MonoBehaviour { //Subordinate pool private string hostPoolId; public string HostPoolId { get { return hostPoolId; } set { hostPoolId = value; } } /// <summary> ///When removing /// </summary> public abstract void OnSpawn(); /// <summary> ///When recycling /// </summary> public abstract void OnUnSpawn(); /// <summary> ///Reset /// </summary> public abstract void Reset(); }
Image source: http://www.coubai.com/ Web game