From 4a0465450a0940f697978bdd7d5cf156117efb80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com>
Date: Wed, 25 Mar 2026 18:29:53 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DGameObjectPool=20class?=
=?UTF-8?q?=E6=9C=AA=E6=B1=A0=E5=8C=96=E7=9A=84=E5=BC=80=E9=94=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ABase/GameObjectPool/GameObjectPool.cs | 221 +++++++++++++++---
1 file changed, 195 insertions(+), 26 deletions(-)
diff --git a/Runtime/ABase/GameObjectPool/GameObjectPool.cs b/Runtime/ABase/GameObjectPool/GameObjectPool.cs
index 984b580..92c7cfa 100644
--- a/Runtime/ABase/GameObjectPool/GameObjectPool.cs
+++ b/Runtime/ABase/GameObjectPool/GameObjectPool.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using AlicizaX;
using AlicizaX.Resource.Runtime;
@@ -71,7 +70,7 @@ namespace AlicizaX
}
[Serializable]
- public class PooledObject
+ public class PooledObject : IMemory
{
public GameObject gameObject;
public string assetPath;
@@ -79,6 +78,7 @@ namespace AlicizaX
public bool isActive;
public string instanceName;
public bool isRefCountReduced;
+ [NonSerialized] public PoolObjectMonitor monitor;
public PooledObject(GameObject go, string path)
{
@@ -90,6 +90,17 @@ namespace AlicizaX
isRefCountReduced = false;
}
+ public void Clear()
+ {
+ gameObject = null;
+ assetPath = null;
+ lastUsedTime = 0f;
+ isActive = false;
+ instanceName = null;
+ isRefCountReduced = false;
+ monitor = null;
+ }
+
///
/// 获取过期进度 (0-1),1表示即将过期。
///
@@ -115,7 +126,7 @@ namespace AlicizaX
/// Inspector显示用的对象信息。
///
[Serializable]
- public class PoolObjectInfo
+ public class PoolObjectInfo : IMemory
{
[SerializeField] public string objectName;
[SerializeField] public string assetPath;
@@ -135,13 +146,24 @@ namespace AlicizaX
expireProgress = pooledObj.GetExpireProgress(expireTime);
gameObject = pooledObj.gameObject;
}
+
+ public void Clear()
+ {
+ objectName = null;
+ assetPath = null;
+ isActive = false;
+ lastUsedTime = 0f;
+ remainingTime = 0f;
+ expireProgress = 0f;
+ gameObject = null;
+ }
}
///
/// Inspector显示用的预制体信息.
///
[Serializable]
- public class PrefabRefInfoDisplay
+ public class PrefabRefInfoDisplay : IMemory
{
[SerializeField] public string assetPath;
[SerializeField] public int refCount;
@@ -155,13 +177,21 @@ namespace AlicizaX
lastAccessTime = info.LastAccessTime;
prefab = info.Prefab;
}
+
+ public void Clear()
+ {
+ assetPath = null;
+ refCount = 0;
+ lastAccessTime = 0f;
+ prefab = null;
+ }
}
///
/// Inspector显示用的池信息。
///
[Serializable]
- public class ConfigPoolInfo
+ public class ConfigPoolInfo : IMemory
{
[SerializeField] public string configAsset;
[SerializeField] public int maxCount;
@@ -198,7 +228,6 @@ namespace AlicizaX
assetPaths.Clear();
assetPaths.AddRange(pool.LoadedPrefabs.Keys);
- objects.Clear();
int objectIndex = 0;
foreach (var pooledObj in pool.AllObjects)
{
@@ -211,7 +240,7 @@ namespace AlicizaX
}
else
{
- info = new PoolObjectInfo();
+ info = MemoryPool.Acquire();
objects.Add(info);
}
@@ -219,8 +248,8 @@ namespace AlicizaX
objectIndex++;
}
}
+ ReleasePoolObjectInfos(objectIndex);
- prefabRefs.Clear();
int prefabIndex = 0;
foreach (var kvp in pool.LoadedPrefabs)
{
@@ -231,13 +260,48 @@ namespace AlicizaX
}
else
{
- info = new PrefabRefInfoDisplay();
+ info = MemoryPool.Acquire();
prefabRefs.Add(info);
}
info.UpdateFromPrefabRefInfo(kvp.Value);
prefabIndex++;
}
+ ReleasePrefabRefInfos(prefabIndex);
+ }
+
+ public void Clear()
+ {
+ configAsset = null;
+ maxCount = 0;
+ expireTime = 0f;
+ totalObjects = 0;
+ activeObjects = 0;
+ availableObjects = 0;
+ loadedPrefabs = 0;
+ assetPaths.Clear();
+ ReleasePoolObjectInfos(0);
+ ReleasePrefabRefInfos(0);
+ }
+
+ private void ReleasePoolObjectInfos(int keepCount)
+ {
+ while (objects.Count > keepCount)
+ {
+ int lastIndex = objects.Count - 1;
+ MemoryPool.Release(objects[lastIndex]);
+ objects.RemoveAt(lastIndex);
+ }
+ }
+
+ private void ReleasePrefabRefInfos(int keepCount)
+ {
+ while (prefabRefs.Count > keepCount)
+ {
+ int lastIndex = prefabRefs.Count - 1;
+ MemoryPool.Release(prefabRefs[lastIndex]);
+ prefabRefs.RemoveAt(lastIndex);
+ }
}
}
@@ -259,6 +323,7 @@ namespace AlicizaX
// GameObject到PooledObject的快速查找字典
private readonly Dictionary _gameObjectToPooledObject;
+ private readonly List _availableObjectPaths;
// 重用临时队列,避免重复创建。
private static Queue _tempQueue = new Queue();
@@ -277,6 +342,7 @@ namespace AlicizaX
PendingRequests = new Dictionary>>();
LoadingAssets = new HashSet();
_gameObjectToPooledObject = new Dictionary();
+ _availableObjectPaths = new List();
// 创建池根节点。
GameObject poolRootGo = new GameObject($"ConfigPool_{config.asset.Replace('/', '_')}");
@@ -422,7 +488,15 @@ namespace AlicizaX
{
var prefabRefInfo = LoadedPrefabs[assetPath];
GameObject instantiate = GameObject.Instantiate(prefabRefInfo.Prefab);
- var pooledObj = new PooledObject(instantiate, assetPath);
+
+ var pooledObj = MemoryPool.Acquire();
+ pooledObj.gameObject = instantiate;
+ pooledObj.assetPath = assetPath;
+ pooledObj.lastUsedTime = Time.time;
+ pooledObj.isActive = false;
+ pooledObj.instanceName = instantiate.name;
+ pooledObj.isRefCountReduced = false;
+
AllObjects.Add(pooledObj);
_gameObjectToPooledObject[instantiate] = pooledObj;
@@ -435,6 +509,7 @@ namespace AlicizaX
}
monitor.Initialize(this, pooledObj);
+ pooledObj.monitor = monitor;
return pooledObj;
}
@@ -478,10 +553,19 @@ namespace AlicizaX
else
{
// 使用LINQ找到最旧的未使用对象(更高效)
- var oldestObj = AllObjects
- .Where(obj => !obj.isActive)
- .OrderBy(obj => obj.lastUsedTime)
- .FirstOrDefault();
+ PooledObject oldestObj = null;
+ foreach (var obj in AllObjects)
+ {
+ if (obj.isActive)
+ {
+ continue;
+ }
+
+ if (oldestObj == null || obj.lastUsedTime < oldestObj.lastUsedTime)
+ {
+ oldestObj = obj;
+ }
+ }
if (oldestObj != null)
{
@@ -543,10 +627,11 @@ namespace AlicizaX
if (!pooledObj.isRefCountReduced)
{
OnObjectReallyDestroyed(pooledObj);
+ MemoryPool.Release(pooledObj);
}
else
{
- // 只需要从集合中移除
+ // DestroyPooledObject 已调用 Detach,此分支理论上不可达
AllObjects.Remove(pooledObj);
CleanAvailableQueue(pooledObj);
}
@@ -618,8 +703,11 @@ namespace AlicizaX
if (pooledObj.gameObject != null)
{
+ pooledObj.monitor?.Detach();
GameObject.Destroy(pooledObj.gameObject);
}
+
+ MemoryPool.Release(pooledObj);
}
public void CheckExpiredObjects()
@@ -645,10 +733,18 @@ namespace AlicizaX
}
// 重建所有路径的可用队列
- foreach (var kvp in AvailableObjectsByPath.ToList())
+ _availableObjectPaths.Clear();
+ foreach (var assetPath in AvailableObjectsByPath.Keys)
{
- var assetPath = kvp.Key;
- var queue = kvp.Value;
+ _availableObjectPaths.Add(assetPath);
+ }
+
+ foreach (var assetPath in _availableObjectPaths)
+ {
+ if (!AvailableObjectsByPath.TryGetValue(assetPath, out var queue))
+ {
+ continue;
+ }
_tempQueue.Clear();
while (queue.Count > 0)
@@ -707,8 +803,11 @@ namespace AlicizaX
{
if (obj.gameObject != null)
{
+ obj.monitor?.Detach();
GameObject.Destroy(obj.gameObject);
}
+
+ MemoryPool.Release(obj);
}
AllObjects.Clear();
@@ -759,6 +858,12 @@ namespace AlicizaX
_pooledObject = pooledObject;
}
+ public void Detach()
+ {
+ _pool = null;
+ _pooledObject = null;
+ }
+
private void OnDestroy()
{
if (_pool != null && _pooledObject != null)
@@ -806,6 +911,7 @@ namespace AlicizaX
private List _poolConfigs;
private List _configPools;
private Dictionary _gameObjectToPool;
+ private Dictionary _configPoolCache;
// 重用预加载对象列表
private static readonly List _preloadedObjects = new List();
@@ -836,6 +942,7 @@ namespace AlicizaX
_configPools = new List();
_gameObjectToPool = new Dictionary();
+ _configPoolCache = new Dictionary();
try
{
@@ -906,13 +1013,31 @@ namespace AlicizaX
// Editor专用的刷新。
private void UpdateInspectorInfo()
{
- poolInfos.Clear();
+ if (_configPools == null)
+ {
+ ReleaseInspectorInfos(0);
+ return;
+ }
+
+ int poolIndex = 0;
foreach (var pool in _configPools)
{
- var info = new ConfigPoolInfo();
+ ConfigPoolInfo info;
+ if (poolIndex < poolInfos.Count)
+ {
+ info = poolInfos[poolIndex];
+ }
+ else
+ {
+ info = MemoryPool.Acquire();
+ poolInfos.Add(info);
+ }
+
info.UpdateFromPool(pool);
- poolInfos.Add(info);
+ poolIndex++;
}
+
+ ReleaseInspectorInfos(poolIndex);
}
public void SetResourceLoader(IResourceLoader resourceLoader)
@@ -1037,14 +1162,36 @@ namespace AlicizaX
private ConfigPool FindConfigPool(string assetPath)
{
+ if (string.IsNullOrEmpty(assetPath))
+ {
+ return null;
+ }
+
+ if (_configPools == null)
+ {
+ return null;
+ }
+
+ if (_configPoolCache == null)
+ {
+ _configPoolCache = new Dictionary();
+ }
+
+ if (_configPoolCache != null && _configPoolCache.TryGetValue(assetPath, out var cachedPool))
+ {
+ return cachedPool;
+ }
+
foreach (var pool in _configPools)
{
if (pool.MatchesAsset(assetPath))
{
+ _configPoolCache[assetPath] = pool;
return pool;
}
}
+ _configPoolCache[assetPath] = null;
return null;
}
@@ -1058,13 +1205,35 @@ namespace AlicizaX
public void ClearAllPools()
{
- foreach (var pool in _configPools)
+ if (_configPools != null)
{
- pool.Clear();
+ foreach (var pool in _configPools)
+ {
+ pool.Clear();
+ }
}
- _gameObjectToPool.Clear();
- poolInfos.Clear();
+ if (_gameObjectToPool != null)
+ {
+ _gameObjectToPool.Clear();
+ }
+
+ if (_configPoolCache != null)
+ {
+ _configPoolCache.Clear();
+ }
+
+ ReleaseInspectorInfos(0);
+ }
+
+ private void ReleaseInspectorInfos(int keepCount)
+ {
+ while (poolInfos.Count > keepCount)
+ {
+ int lastIndex = poolInfos.Count - 1;
+ MemoryPool.Release(poolInfos[lastIndex]);
+ poolInfos.RemoveAt(lastIndex);
+ }
}
private void OnDestroy()
@@ -1175,7 +1344,7 @@ namespace AlicizaX
{
public static GameObject LoadGameObject(string assetPath, Transform parent = null)
{
- return GameObjectPool.Instance.GetGameObject(assetPath);
+ return GameObjectPool.Instance.GetGameObject(assetPath, parent);
}
public static async UniTask LoadGameObjectAsync(string assetPath, Transform parent = null, CancellationToken cancellationToken = default)