From d5518c46b1d84f3103ad49d35eff6889e93e5b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Mon, 23 Mar 2026 20:50:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=E8=B1=A1=E6=B1=A0?= =?UTF-8?q?=E6=9F=A5=E6=89=BE=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataStruct/GameFrameworkLinkedList.cs | 10 ++ .../GameFrameworkMultiDictionary.cs | 64 +++++-- .../ObjectPool/ObjectPoolManager.Object.cs | 19 ++- .../ObjectPoolManager.ObjectPool.cs | 156 +++++++++++++++--- 4 files changed, 205 insertions(+), 44 deletions(-) diff --git a/Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs b/Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs index 35361ef..97bdf9a 100644 --- a/Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs +++ b/Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs @@ -221,6 +221,16 @@ namespace AlicizaX return m_LinkedList.Contains(value); } + /// + /// 确定指定结点是否在链表中。 + /// + /// 要检查的结点。 + /// 指定结点是否在链表中。 + public bool Contains(LinkedListNode node) + { + return node != null && node.List == m_LinkedList; + } + /// /// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。 /// diff --git a/Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs b/Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs index 0b68d74..081fa01 100644 --- a/Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs +++ b/Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs @@ -101,18 +101,19 @@ namespace AlicizaX /// /// 指定的主键。 /// 指定的值。 - public void Add(TKey key, TValue value) + public LinkedListNode Add(TKey key, TValue value) { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); if (m_Dictionary.TryGetValue(key, out range)) { - m_LinkedList.AddBefore(range.Terminal, value); + return m_LinkedList.AddBefore(range.Terminal, value); } else { LinkedListNode first = m_LinkedList.AddLast(value); LinkedListNode terminal = m_LinkedList.AddLast(default(TValue)); m_Dictionary.Add(key, new GameFrameworkLinkedListRange(first, terminal)); + return first; } } @@ -131,22 +132,7 @@ namespace AlicizaX { if (current.Value.Equals(value)) { - if (current == range.First) - { - LinkedListNode next = current.Next; - if (next == range.Terminal) - { - m_LinkedList.Remove(next); - m_Dictionary.Remove(key); - } - else - { - m_Dictionary[key] = new GameFrameworkLinkedListRange(next, range.Terminal); - } - } - - m_LinkedList.Remove(current); - return true; + return Remove(key, current); } } } @@ -154,6 +140,48 @@ namespace AlicizaX return false; } + /// + /// 从指定的主键中移除指定结点。 + /// + /// 指定的主键。 + /// 要移除的结点。 + /// 是否移除成功。 + public bool Remove(TKey key, LinkedListNode node) + { + if (node == null) + { + return false; + } + + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + if (!m_Dictionary.TryGetValue(key, out range)) + { + return false; + } + + if (!m_LinkedList.Contains(node) || node == range.Terminal) + { + return false; + } + + if (node == range.First) + { + LinkedListNode next = node.Next; + if (next == range.Terminal) + { + m_LinkedList.Remove(next); + m_Dictionary.Remove(key); + } + else + { + m_Dictionary[key] = new GameFrameworkLinkedListRange(next, range.Terminal); + } + } + + m_LinkedList.Remove(node); + return true; + } + /// /// 从指定的主键中移除所有的值。 /// diff --git a/Runtime/ABase/ObjectPool/ObjectPoolManager.Object.cs b/Runtime/ABase/ObjectPool/ObjectPoolManager.Object.cs index c534df1..c9a8933 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolManager.Object.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolManager.Object.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using AlicizaX; namespace AlicizaX.ObjectPool @@ -11,16 +12,20 @@ namespace AlicizaX.ObjectPool /// 对象类型。 private sealed class Object : IMemory where T : ObjectBase { + private string m_Name; private T m_Object; private int m_SpawnCount; + private LinkedListNode> m_NameNode; /// /// 初始化内部对象的新实例。 /// public Object() { + m_Name = null; m_Object = null; m_SpawnCount = 0; + m_NameNode = null; } /// @@ -28,7 +33,7 @@ namespace AlicizaX.ObjectPool /// public string Name { - get { return m_Object.Name; } + get { return m_Name; } } /// @@ -81,6 +86,15 @@ namespace AlicizaX.ObjectPool get { return m_SpawnCount; } } + /// + /// 获取或设置对象在名字桶中的链表结点。 + /// + public LinkedListNode> NameNode + { + get { return m_NameNode; } + internal set { m_NameNode = value; } + } + /// /// 创建内部对象。 /// @@ -95,6 +109,7 @@ namespace AlicizaX.ObjectPool } Object internalObject = MemoryPool.Acquire>(); + internalObject.m_Name = obj.Name; internalObject.m_Object = obj; internalObject.m_SpawnCount = spawned ? 1 : 0; if (spawned) @@ -110,8 +125,10 @@ namespace AlicizaX.ObjectPool /// public void Clear() { + m_Name = null; m_Object = null; m_SpawnCount = 0; + m_NameNode = null; } /// diff --git a/Runtime/ABase/ObjectPool/ObjectPoolManager.ObjectPool.cs b/Runtime/ABase/ObjectPool/ObjectPoolManager.ObjectPool.cs index f3afb9f..1c7dd19 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolManager.ObjectPool.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolManager.ObjectPool.cs @@ -15,8 +15,10 @@ namespace AlicizaX.ObjectPool private readonly GameFrameworkMultiDictionary> m_Objects; private readonly Dictionary> m_ObjectMap; private readonly ReleaseObjectFilterCallback m_DefaultReleaseObjectFilterCallback; - private readonly List m_CachedCanReleaseObjects; - private readonly List m_CachedToReleaseObjects; + private readonly List> m_CachedCanReleaseObjects; + private readonly List> m_CachedToReleaseObjects; + private readonly List m_CachedCanReleaseTargets; + private readonly IComparer> m_ReleaseObjectComparer; private readonly bool m_AllowMultiSpawn; private float m_AutoReleaseInterval; private int m_Capacity; @@ -39,8 +41,10 @@ namespace AlicizaX.ObjectPool m_Objects = new GameFrameworkMultiDictionary>(); m_ObjectMap = new Dictionary>(); m_DefaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback; - m_CachedCanReleaseObjects = new List(); - m_CachedToReleaseObjects = new List(); + m_CachedCanReleaseObjects = new List>(); + m_CachedToReleaseObjects = new List>(); + m_CachedCanReleaseTargets = new List(); + m_ReleaseObjectComparer = Comparer>.Create(ReleaseObjectComparer); m_AllowMultiSpawn = allowMultiSpawn; m_AutoReleaseInterval = autoReleaseInterval; Capacity = capacity; @@ -163,7 +167,7 @@ namespace AlicizaX.ObjectPool } Object internalObject = Object.Create(obj, spawned); - m_Objects.Add(obj.Name, internalObject); + internalObject.NameNode = m_Objects.Add(internalObject.Name, internalObject); m_ObjectMap.Add(obj.Target, internalObject); if (Count > m_Capacity) @@ -393,17 +397,7 @@ namespace AlicizaX.ObjectPool return false; } - if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) - { - return false; - } - - m_Objects.Remove(internalObject.Name, internalObject); - m_ObjectMap.Remove(internalObject.Peek().Target); - - internalObject.Release(false); - MemoryPool.Release(internalObject); - return true; + return ReleaseObject(internalObject); } /// @@ -444,6 +438,12 @@ namespace AlicizaX.ObjectPool throw new GameFrameworkException("Release object filter callback is invalid."); } + if (releaseObjectFilterCallback == m_DefaultReleaseObjectFilterCallback) + { + ReleaseWithDefaultFilter(toReleaseCount); + return; + } + if (toReleaseCount < 0) { toReleaseCount = 0; @@ -457,7 +457,13 @@ namespace AlicizaX.ObjectPool m_AutoReleaseTime = 0f; GetCanReleaseObjects(m_CachedCanReleaseObjects); - List toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseObjects, toReleaseCount, expireTime); + m_CachedCanReleaseTargets.Clear(); + foreach (Object internalObject in m_CachedCanReleaseObjects) + { + m_CachedCanReleaseTargets.Add(internalObject.Peek()); + } + + List toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseTargets, toReleaseCount, expireTime); if (toReleaseObjects == null || toReleaseObjects.Count <= 0) { return; @@ -476,7 +482,7 @@ namespace AlicizaX.ObjectPool { m_AutoReleaseTime = 0f; GetCanReleaseObjects(m_CachedCanReleaseObjects); - foreach (T toReleaseObject in m_CachedCanReleaseObjects) + foreach (Object toReleaseObject in m_CachedCanReleaseObjects) { ReleaseObject(toReleaseObject); } @@ -523,6 +529,7 @@ namespace AlicizaX.ObjectPool m_ObjectMap.Clear(); m_CachedCanReleaseObjects.Clear(); m_CachedToReleaseObjects.Clear(); + m_CachedCanReleaseTargets.Clear(); } private Object GetObject(object target) @@ -541,7 +548,95 @@ namespace AlicizaX.ObjectPool return null; } - private void GetCanReleaseObjects(List results) + private bool ReleaseObject(Object internalObject) + { + if (internalObject == null) + { + return false; + } + + if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) + { + return false; + } + + T targetObject = internalObject.Peek(); + if (targetObject == null) + { + return false; + } + + if (!m_Objects.Remove(internalObject.Name, internalObject.NameNode)) + { + m_Objects.Remove(internalObject.Name, internalObject); + } + + internalObject.NameNode = null; + m_ObjectMap.Remove(targetObject.Target); + + internalObject.Release(false); + MemoryPool.Release(internalObject); + return true; + } + + private void ReleaseWithDefaultFilter(int toReleaseCount) + { + if (toReleaseCount < 0) + { + toReleaseCount = 0; + } + + DateTime expireTime = DateTime.MinValue; + bool checkExpire = m_ExpireTime < float.MaxValue; + if (checkExpire) + { + expireTime = DateTime.UtcNow.AddSeconds(-m_ExpireTime); + } + + m_AutoReleaseTime = 0f; + if (Count <= 0 || (toReleaseCount <= 0 && !checkExpire)) + { + return; + } + + GetCanReleaseObjects(m_CachedCanReleaseObjects); + if (m_CachedCanReleaseObjects.Count <= 0) + { + return; + } + + m_CachedToReleaseObjects.Clear(); + int remainingCount = 0; + for (int i = 0; i < m_CachedCanReleaseObjects.Count; i++) + { + Object candidateObject = m_CachedCanReleaseObjects[i]; + if (checkExpire && candidateObject.LastUseTime <= expireTime) + { + m_CachedToReleaseObjects.Add(candidateObject); + continue; + } + + m_CachedCanReleaseObjects[remainingCount++] = candidateObject; + } + + int additionalReleaseCount = toReleaseCount - m_CachedToReleaseObjects.Count; + if (additionalReleaseCount > 0 && remainingCount > 0) + { + m_CachedCanReleaseObjects.Sort(0, remainingCount, m_ReleaseObjectComparer); + int takeCount = additionalReleaseCount < remainingCount ? additionalReleaseCount : remainingCount; + for (int i = 0; i < takeCount; i++) + { + m_CachedToReleaseObjects.Add(m_CachedCanReleaseObjects[i]); + } + } + + foreach (Object toReleaseObject in m_CachedToReleaseObjects) + { + ReleaseObject(toReleaseObject); + } + } + + private void GetCanReleaseObjects(List> results) { if (results == null) { @@ -557,13 +652,13 @@ namespace AlicizaX.ObjectPool continue; } - results.Add(internalObject.Peek()); + results.Add(internalObject); } } private List DefaultReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) { - m_CachedToReleaseObjects.Clear(); + m_CachedCanReleaseTargets.Clear(); if (expireTime > DateTime.MinValue) { @@ -571,13 +666,13 @@ namespace AlicizaX.ObjectPool { if (candidateObjects[i].LastUseTime <= expireTime) { - m_CachedToReleaseObjects.Add(candidateObjects[i]); + m_CachedCanReleaseTargets.Add(candidateObjects[i]); candidateObjects.RemoveAt(i); continue; } } - toReleaseCount -= m_CachedToReleaseObjects.Count; + toReleaseCount -= m_CachedCanReleaseTargets.Count; } for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++) @@ -593,11 +688,22 @@ namespace AlicizaX.ObjectPool } } - m_CachedToReleaseObjects.Add(candidateObjects[i]); + m_CachedCanReleaseTargets.Add(candidateObjects[i]); toReleaseCount--; } - return m_CachedToReleaseObjects; + return m_CachedCanReleaseTargets; + } + + private static int ReleaseObjectComparer(Object a, Object b) + { + int priorityCompare = a.Priority.CompareTo(b.Priority); + if (priorityCompare != 0) + { + return priorityCompare; + } + + return a.LastUseTime.CompareTo(b.LastUseTime); } } }