Procházet zdrojové kódy

更新非托管容器库 (#493)

1. 添加自定义非托管内存池 加速内存分配 减少碎片
2. 修复multimap clear 没有释放list对象的bug
susices před 2 roky
rodič
revize
e8cbedd6dc
18 změnil soubory, kde provedl 548 přidání a 91 odebrání
  1. 8 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool.meta
  2. 125 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/FixedSizeMemoryPool.cs
  3. 1 1
      Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/FixedSizeMemoryPool.cs.meta
  4. 205 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/Slab.cs
  5. 11 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/Slab.cs.meta
  6. 6 6
      Unity/Assets/Scripts/ThirdParty/NativeCollection/Map.cs
  7. 13 6
      Unity/Assets/Scripts/ThirdParty/NativeCollection/MultiMap.cs
  8. 2 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/NativeMemoryHelper.cs
  9. 4 4
      Unity/Assets/Scripts/ThirdParty/NativeCollection/NativePool.cs
  10. 6 6
      Unity/Assets/Scripts/ThirdParty/NativeCollection/SortedSet.cs
  11. 16 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/List.cs
  12. 2 2
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/Map/Map.cs
  13. 37 10
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/MultiMap/MultiMap.cs
  14. 20 7
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/MultiMap/MultiMapPair.cs
  15. 9 3
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativeStackPool.cs
  16. 11 0
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativeStackPool.cs.meta
  17. 36 19
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/SortedSet/Node.cs
  18. 36 27
      Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/SortedSet/SortedSet.cs

+ 8 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 19cd1b59a95a1ae4f8403bf8962404a4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 125 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/FixedSizeMemoryPool.cs

@@ -0,0 +1,125 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace NativeCollection
+{
+    public unsafe partial struct FixedSizeMemoryPool: IDisposable
+    {
+        // 最大维护的空slab 多出的空slab直接释放
+        public int MaxUnUsedSlabs;
+        
+        public int ItemSize;
+
+        public int BlockSize;
+
+        public SlabLinkedList InUsedSlabs;
+
+        public SlabLinkedList UnUsedSlabs;
+        public FixedSizeMemoryPool* Self
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return (FixedSizeMemoryPool*)Unsafe.AsPointer(ref this); }
+        }
+
+        public static FixedSizeMemoryPool* Create(int blockSize, int itemSize , int maxUnUsedSlabs = 3)
+        {
+            FixedSizeMemoryPool* memoryPool = (FixedSizeMemoryPool*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<FixedSizeMemoryPool>());
+            memoryPool->ItemSize = itemSize;
+            memoryPool->BlockSize = blockSize;
+            memoryPool->MaxUnUsedSlabs = maxUnUsedSlabs;
+            Slab* initSlab = Slab.Create(blockSize, itemSize,null,null);
+            memoryPool->InUsedSlabs = new SlabLinkedList(initSlab);
+            memoryPool->UnUsedSlabs = new SlabLinkedList(null);
+            return memoryPool;
+        }
+
+        public void* Alloc()
+        {
+            Debug.Assert(InUsedSlabs.Top!=null && InUsedSlabs.Top->FreeSize>0);
+            byte* allocPtr = InUsedSlabs.Top->Alloc();
+            
+            if (InUsedSlabs.Top->IsAllAlloc())
+            {
+                InUsedSlabs.MoveTopToBottom();
+                
+                if (InUsedSlabs.Top->IsAllAlloc())
+                {
+                    Slab* newSlab = Slab.Create(BlockSize, ItemSize,null,null);
+                    InUsedSlabs.AddToTop(newSlab);
+                }
+            }
+            return allocPtr;
+        }
+
+        public void Free(void* ptr)
+        {
+            Debug.Assert(ptr!=null);
+            ListNode* listNode = (ListNode*)((byte*)ptr - Unsafe.SizeOf<ListNode>());
+            Debug.Assert(listNode!=null);
+
+            Slab* slab = listNode->ParentSlab;
+            slab->Free(listNode);
+            
+            if (slab==InUsedSlabs.Top)
+            {
+                return;
+            }
+            
+            // 当前链表头为空时 移至空闲链表
+            if (InUsedSlabs.Top->IsAllFree())
+            {
+                Slab* oldTopSlab = InUsedSlabs.Top;
+                InUsedSlabs.SplitOut(oldTopSlab);
+                UnUsedSlabs.AddToTop(oldTopSlab);
+                
+                // 释放多于的空slab
+                if (UnUsedSlabs.SlabCount>MaxUnUsedSlabs)
+                {
+                    var bottomSlab = UnUsedSlabs.Bottom;
+                    UnUsedSlabs.SplitOut(bottomSlab);
+                    bottomSlab->Dispose();
+                }
+            }
+                
+            // 对应slab移至链表头部
+            if (slab!=InUsedSlabs.Top)
+            {
+                InUsedSlabs.SplitOut(slab);
+                InUsedSlabs.AddToTop(slab);
+            }
+        }
+
+        public void ReleaseUnUsedSlabs()
+        {
+            Slab* unUsedSlab = UnUsedSlabs.Top;
+            while (unUsedSlab!=null)
+            {
+                Slab* currentSlab = unUsedSlab;
+                unUsedSlab = unUsedSlab->Next;
+                currentSlab->Dispose();
+            }
+            UnUsedSlabs = new SlabLinkedList(null);
+        }
+        
+        public void Dispose()
+        {
+            Slab* inUsedSlab = InUsedSlabs.Top;
+            while (inUsedSlab!=null)
+            {
+                Slab* currentSlab = inUsedSlab;
+                inUsedSlab = inUsedSlab->Next;
+                currentSlab->Dispose();
+            }
+
+            ReleaseUnUsedSlabs();
+
+            if (Self!=null)
+            {
+                NativeMemoryHelper.Free(Self);
+                NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<FixedSizeMemoryPool>());
+            }
+        }
+    }
+}
+

+ 1 - 1
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativePool.cs.meta → Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/FixedSizeMemoryPool.cs.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 439d2651b8f470f418c65bffa99269fb
+guid: 28fd7d4bb9a824847b548d99ccf75eea
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2

+ 205 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/Slab.cs

@@ -0,0 +1,205 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace NativeCollection
+{
+    public unsafe partial struct FixedSizeMemoryPool
+    {
+        public struct Slab : IDisposable
+        {
+            public int BlockSize;
+            
+            public int FreeSize;
+
+            public int ItemSize;
+
+            public ListNode* FreeList;
+
+            public Slab* Prev;
+
+            public Slab* Next;
+
+            public Slab* Self
+            {
+                [MethodImpl(MethodImplOptions.AggressiveInlining)]
+                get { return (Slab*)Unsafe.AsPointer(ref this); }
+            }
+
+            public static Slab* Create(int blockSize,int itemSize,Slab* prevSlab , Slab* nextSlab )
+            {
+                int size = itemSize + Unsafe.SizeOf<IntPtr>();
+                int slabSize =Unsafe.SizeOf<Slab>() + size * blockSize;
+                byte* slabBuffer  = (byte*)NativeMemoryHelper.Alloc((UIntPtr)slabSize);
+                Slab* slab = (Slab*)slabBuffer;
+                slab->BlockSize = blockSize;
+                slab->FreeSize = blockSize;
+                slab->ItemSize = itemSize;
+                slab->Prev = prevSlab;
+                slab->Next = nextSlab;
+                slabBuffer+=Unsafe.SizeOf<Slab>();
+
+                ListNode* next = null;
+                
+                for (int i = blockSize-1; i >= 0; i--)
+                {
+                    ListNode* listNode = (ListNode*)(slabBuffer + i*size);
+                    listNode->Next = next;
+                    next = listNode;
+                }
+
+                slab->FreeList = next;
+                return slab;
+            }
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            public byte* Alloc()
+            {
+                Debug.Assert(FreeList!=null && FreeSize>0);
+                FreeSize--;
+                ListNode* node = FreeList;
+                FreeList = FreeList->Next;
+                node->ParentSlab = Self;
+                node += 1;
+                return (byte*)node;
+            }
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            public void Free(ListNode* node)
+            {
+                Debug.Assert(FreeSize<BlockSize && node!=null);
+                FreeSize++;
+                node->Next = FreeList;
+                FreeList = node;
+            }
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            public bool IsAllFree()
+            {
+                return FreeSize == BlockSize;
+            }
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            public bool IsAllAlloc()
+            {
+                return FreeSize == 0;
+            }
+            
+            public void Dispose()
+            {
+                int slabSize =Unsafe.SizeOf<Slab>() + (ItemSize + Unsafe.SizeOf<IntPtr>()) * BlockSize;
+                Slab* self = Self;
+                NativeMemoryHelper.Free(self);
+                NativeMemoryHelper.RemoveNativeMemoryByte(slabSize);
+            }
+        }
+        
+        [StructLayout(LayoutKind.Explicit)]
+        public struct ListNode
+        {
+            [FieldOffset(0)]
+            public ListNode* Next;
+            [FieldOffset(0)]
+            public Slab* ParentSlab;
+        }
+        
+        public struct SlabLinkedList
+        {
+            public int SlabCount;
+            public Slab* Top;
+            public Slab* Bottom;
+
+            public SlabLinkedList(Slab* initSlab)
+            {
+                Top = initSlab;
+                Bottom = initSlab;
+                SlabCount = initSlab==null?0:1;
+            }
+
+            public void MoveTopToBottom()
+            {
+                Debug.Assert(Top!=null && Bottom!=null);
+                if (Top==Bottom)
+                {
+                    return;
+                }
+
+                Slab* oldTop = Top;
+                Top = Top->Next;
+                Top->Prev = null;
+                Bottom->Next = oldTop;
+                oldTop->Prev = Bottom;
+                oldTop->Next = null;
+                Bottom = oldTop;
+            }
+
+            public void SplitOut(Slab* splitSlab)
+            {
+                Debug.Assert(splitSlab!=null && Top!=null && Bottom!=null);
+
+                SlabCount--;
+                // 只有一个slab
+                if (Top==Bottom)
+                {
+                    splitSlab->Prev = null;
+                    splitSlab->Next = null;
+                    Top = null;
+                    Bottom = null;
+                    return;
+                }
+                
+                // 链表头部
+                if (splitSlab == Top)
+                {
+                    Top = splitSlab->Next;
+                    splitSlab->Next = null;
+                    Top->Prev = null;
+                    return;
+                }
+
+                if (splitSlab == Bottom)
+                {
+                    Bottom = splitSlab->Prev;
+                    Bottom->Next = null;
+                    splitSlab->Prev = null;
+                    return;
+                }
+
+                var prev = splitSlab->Prev;
+                var next = splitSlab->Next;
+                prev->Next = next;
+                next->Prev = prev;
+                splitSlab->Prev = null;
+                splitSlab->Next = null;
+            }
+
+            public void AddToTop(Slab* slab)
+            {
+                SlabCount++;
+                if (Top == Bottom)
+                {
+                    if (Top==null)
+                    {
+                        Top = slab;
+                        Bottom = slab;
+                        slab->Prev = null;
+                        slab->Next = null;
+                    }
+                    else
+                    {
+                        Slab* oldTop = Top;
+                        Top = slab;
+                        Top->Next = oldTop;
+                        Top->Prev = null;
+                        oldTop->Prev = Top;
+                    }
+                    return;
+                }
+
+                Slab* oldSlab = Top;
+                Top = slab;
+                Top->Next = oldSlab;
+                Top->Prev = null;
+                oldSlab->Prev = Top;
+            }
+        }
+    }
+}
+

+ 11 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/FixedSizeMemoryPool/Slab.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8b0d7bf635c106144886a5284ae0705e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 6 - 6
Unity/Assets/Scripts/ThirdParty/NativeCollection/Map.cs

@@ -9,14 +9,14 @@ namespace NativeCollection
     public unsafe class Map<T, K> : IEnumerable<MapPair<T, K>>, INativeCollectionClass
         where T : unmanaged, IEquatable<T>, IComparable<T> where K : unmanaged, IEquatable<K>
     {
-        private const int _defaultPoolSize = 50;
-        private int _poolSize;
+        private const int _defaultPoolBlockSize = 64;
+        private int _poolBlockSize;
         private UnsafeType.Map<T, K>* _map;
     
-        public Map(int maxPoolSize = _defaultPoolSize)
+        public Map(int poolBlockSize = _defaultPoolBlockSize)
         {
-            _poolSize = maxPoolSize;
-            _map = UnsafeType.Map<T, K>.Create(_poolSize);
+            _poolBlockSize = poolBlockSize;
+            _map = UnsafeType.Map<T, K>.Create(_poolBlockSize);
             IsDisposed = false;
         }
     
@@ -54,7 +54,7 @@ namespace NativeCollection
         {
             if (IsDisposed)
             {
-                _map = UnsafeType.Map<T, K>.Create(_poolSize);
+                _map = UnsafeType.Map<T, K>.Create(_poolBlockSize);
                 IsDisposed = false;
             }
         }

+ 13 - 6
Unity/Assets/Scripts/ThirdParty/NativeCollection/MultiMap.cs

@@ -11,14 +11,19 @@ namespace NativeCollection
 {
     private UnsafeType.MultiMap<T, K>* _multiMap;
 
-    private const int _defaultPoolSize = 200;
+    private const int _defaultPoolBlockSize = 64;
 
-    private int _poolSize;
+    private const int _defaultListPoolSize = 200;
+
+    private int _poolBlockSize;
+
+    private int _listPoolSize;
     
-    public MultiMap(int maxPoolSize = _defaultPoolSize)
+    public MultiMap(int listPoolSize = _defaultListPoolSize,int nodePoolBlockSize = _defaultPoolBlockSize)
     {
-        _poolSize = maxPoolSize;
-        _multiMap = UnsafeType.MultiMap<T, K>.Create(_poolSize);
+        _poolBlockSize = nodePoolBlockSize;
+        _listPoolSize = listPoolSize;
+        _multiMap = UnsafeType.MultiMap<T, K>.Create(_poolBlockSize,_listPoolSize);
         IsDisposed = false;
     }
     
@@ -72,8 +77,10 @@ namespace NativeCollection
         {
             return;
         }
+        
         if (_multiMap!=null)
         {
+            
             _multiMap->Dispose();
             NativeMemoryHelper.Free(_multiMap);
             NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<UnsafeType.MultiMap<T,K>>());
@@ -85,7 +92,7 @@ namespace NativeCollection
     {
         if (IsDisposed)
         {
-            _multiMap = UnsafeType.MultiMap<T, K>.Create(_poolSize);
+            _multiMap = UnsafeType.MultiMap<T, K>.Create(_poolBlockSize,_listPoolSize);
             IsDisposed = false;
         }
     }

+ 2 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/NativeMemoryHelper.cs

@@ -73,6 +73,7 @@ namespace NativeCollection
         public static void AddNativeMemoryByte(long size)
         {
             GC.AddMemoryPressure((long)size);
+            //Console.WriteLine($"AddNativeMemoryByte {size}");
 #if MEMORY_PROFILE
             NativeMemoryBytes += size;
 #endif
@@ -81,6 +82,7 @@ namespace NativeCollection
         public static void RemoveNativeMemoryByte(long size)
         {
             GC.RemoveMemoryPressure(size);
+            //Console.WriteLine($"RemoveMemoryPressure {size}");
 #if MEMORY_PROFILE
             NativeMemoryBytes -= size;
 #endif

+ 4 - 4
Unity/Assets/Scripts/ThirdParty/NativeCollection/NativePool.cs

@@ -6,13 +6,13 @@ namespace NativeCollection
 {
     public unsafe class NativePool<T> : INativeCollectionClass where T: unmanaged,IEquatable<T>,IPool
     {
-        private UnsafeType.NativePool<T>* _nativePool;
+        private UnsafeType.NativeStackPool<T>* _nativePool;
         private const int _defaultPoolSize = 200;
         private int _poolSize;
         public NativePool(int maxPoolSize = _defaultPoolSize)
         {
             _poolSize = maxPoolSize;
-            _nativePool = UnsafeType.NativePool<T>.Create(_poolSize);
+            _nativePool = UnsafeType.NativeStackPool<T>.Create(_poolSize);
             IsDisposed = false;
         }
         
@@ -38,7 +38,7 @@ namespace NativeCollection
             {
                 _nativePool->Dispose();
                 NativeMemoryHelper.Free(_nativePool);
-                NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<UnsafeType.NativePool<T>>());
+                NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<UnsafeType.NativeStackPool<T>>());
                 IsDisposed = true;
             }
         }
@@ -47,7 +47,7 @@ namespace NativeCollection
         {
             if (IsDisposed)
             {
-                _nativePool = UnsafeType.NativePool<T>.Create(_poolSize);
+                _nativePool = UnsafeType.NativeStackPool<T>.Create(_poolSize);
                 IsDisposed = false;
             }
         }

+ 6 - 6
Unity/Assets/Scripts/ThirdParty/NativeCollection/SortedSet.cs

@@ -8,12 +8,12 @@ namespace NativeCollection
     public unsafe class SortedSet<T> : ICollection<T>, INativeCollectionClass where T : unmanaged, IEquatable<T>,IComparable<T>
 {
     private UnsafeType.SortedSet<T>* _sortedSet;
-    private const int _defaultNodePoolSize = 200;
-    private int _poolSize;
-    public SortedSet(int nodePoolSize = _defaultNodePoolSize)
+    private const int _defaultNodePoolBlockSize = 64;
+    private int _poolBlockSize;
+    public SortedSet(int nodePoolSize = _defaultNodePoolBlockSize)
     {
-        _poolSize = nodePoolSize;
-        _sortedSet = UnsafeType.SortedSet<T>.Create(_poolSize);
+        _poolBlockSize = nodePoolSize;
+        _sortedSet = UnsafeType.SortedSet<T>.Create(_poolBlockSize);
         IsDisposed = false;
     }
     IEnumerator<T> IEnumerable<T>.GetEnumerator()
@@ -92,7 +92,7 @@ namespace NativeCollection
     {
         if (IsDisposed)
         {
-            _sortedSet = UnsafeType.SortedSet<T>.Create(_poolSize);
+            _sortedSet = UnsafeType.SortedSet<T>.Create(_poolBlockSize);
             IsDisposed = false;
         }
     }

+ 16 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/List.cs

@@ -33,6 +33,22 @@ namespace NativeCollection.UnsafeType
         return list;
     }
 
+    public static List<T>* AllocFromMemoryPool(FixedSizeMemoryPool* memoryPool,int initialCapacity = _defaultCapacity)
+    {
+        if (initialCapacity < 0) ThrowHelper.ListInitialCapacityException();
+
+        var list = (List<T>*)memoryPool->Alloc();
+
+        if (initialCapacity < _defaultCapacity)
+            initialCapacity = _defaultCapacity; // Simplify doubling logic in Push.
+
+        list->_items = (T*)NativeMemoryHelper.Alloc((UIntPtr)initialCapacity, (UIntPtr)Unsafe.SizeOf<T>());
+        list->_arrayLength = initialCapacity;
+        list->Count = 0;
+        list->self = list;
+        return list;
+    }
+
     
     public ref T this[int index]
     {

+ 2 - 2
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/Map/Map.cs

@@ -10,10 +10,10 @@ namespace NativeCollection.UnsafeType
 {
     private UnsafeType.SortedSet<MapPair<T, K>>* _sortedSet;
     
-    public static Map<T, K>* Create(int maxPoolSize)
+    public static Map<T, K>* Create(int poolBlockSize)
     {
         Map<T, K>* map = (Map<T, K>*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<Map<T, K>>());
-        map->_sortedSet = UnsafeType.SortedSet<MapPair<T, K>>.Create(maxPoolSize);
+        map->_sortedSet = UnsafeType.SortedSet<MapPair<T, K>>.Create(poolBlockSize);
         return map;
     }
     

+ 37 - 10
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/MultiMap/MultiMap.cs

@@ -10,13 +10,16 @@ namespace NativeCollection.UnsafeType
 {
     private UnsafeType.SortedSet<MultiMapPair<T, K>>* _sortedSet;
 
-    private NativePool<List<K>>* _listPool;
+    private FixedSizeMemoryPool* _listMemoryPool;
 
-    public static MultiMap<T, K>* Create(int maxPoolSize)
+    private NativeStackPool<List<K>>* _listStackPool;
+
+    public static MultiMap<T, K>* Create(int poolBlockSize,int listPoolSize)
     {
         MultiMap<T, K>* multiMap = (MultiMap<T, K>*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<MultiMap<T, K>>());
-        multiMap->_sortedSet = UnsafeType.SortedSet<MultiMapPair<T, K>>.Create(maxPoolSize);
-        multiMap->_listPool = NativePool<List<K>>.Create(maxPoolSize);
+        multiMap->_sortedSet = UnsafeType.SortedSet<MultiMapPair<T, K>>.Create(poolBlockSize);
+        multiMap->_listMemoryPool = FixedSizeMemoryPool.Create(poolBlockSize,Unsafe.SizeOf<List<K>>());
+        multiMap->_listStackPool = NativeStackPool<List<K>>.Create(listPoolSize);
         return multiMap;
     }
 
@@ -44,7 +47,7 @@ namespace NativeCollection.UnsafeType
         }
         else
         {
-            list = MultiMapPair<T, K>.Create(key,_listPool);
+            list = MultiMapPair<T, K>.Create(key,_listMemoryPool,_listStackPool);
             _sortedSet->AddRef(list);
         }
         list.Value.AddRef(value);
@@ -76,14 +79,31 @@ namespace NativeCollection.UnsafeType
         if (node == null) return false;
         list = node->Item;
         var sortedSetRemove = _sortedSet->RemoveRef(list);
-        list.Dispose(_listPool);
+        list.Dispose(_listMemoryPool,_listStackPool);
         return sortedSetRemove;
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     public void Clear()
     {
+        using var enumerator = GetEnumerator();
+        do
+        {
+            if (enumerator.CurrentPointer != null)
+            {
+                enumerator.CurrentPointer->Item.Dispose(_listMemoryPool,_listStackPool);
+            }
+        } while (enumerator.MoveNext());
+
+        List<K>* list = _listStackPool->Alloc();
+        while (list!=null)
+        {
+            list->Dispose();
+            _listMemoryPool->Free(list);
+            list = _listStackPool->Alloc();
+        }
         _sortedSet->Clear();
+        _listMemoryPool->ReleaseUnUsedSlabs();
     }
 
     public int Count => _sortedSet->Count;
@@ -110,16 +130,23 @@ namespace NativeCollection.UnsafeType
     {
         if (_sortedSet != null)
         {
+            Clear();
             _sortedSet->Dispose();
             NativeMemoryHelper.Free(_sortedSet);
             NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<UnsafeType.SortedSet<MultiMapPair<T, K>>>());
         }
+        
+        if (_listStackPool!=null)
+        {
+            _listStackPool->Dispose();
+            NativeMemoryHelper.Free(_listStackPool);
+            NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<NativeStackPool<List<K>>>());
+        }
 
-        if (_listPool!=null)
+        if (_listMemoryPool!=null)
         {
-            _listPool->Dispose();
-            NativeMemoryHelper.Free(_listPool);
-            NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<NativePool<List<K>>>());
+            _listMemoryPool->Dispose();
+            _listMemoryPool = null;
         }
     }
 }

+ 20 - 7
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/MultiMap/MultiMapPair.cs

@@ -10,8 +10,12 @@ namespace NativeCollection.UnsafeType
         
         public T Key { get; private set; }
     
-        public ref UnsafeType.List<K> Value => ref Unsafe.AsRef<UnsafeType.List<K>>(_value);
-    
+        public ref UnsafeType.List<K> Value
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return ref Unsafe.AsRef<UnsafeType.List<K>>(_value); }
+        }
+
         public MultiMapPair(T key)
         {
             Key = key;
@@ -19,13 +23,13 @@ namespace NativeCollection.UnsafeType
         }
     
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static MultiMapPair<T, K> Create(in T key, NativePool<List<K>>* pool)
+        public static MultiMapPair<T, K> Create(in T key, FixedSizeMemoryPool* pool, NativeStackPool<List<K>>* stackPool)
         {
             var pair = new MultiMapPair<T, K>(key);
-            var list = pool->Alloc();
+            List<K>* list = stackPool->Alloc();
             if (list==null)
             {
-                list = List<K>.Create();
+                list = List<K>.AllocFromMemoryPool(pool);
             }
             pair._value = list;
             return pair;
@@ -50,11 +54,20 @@ namespace NativeCollection.UnsafeType
         }
     
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public void Dispose(NativePool<List<K>>* pool)
+        public void Dispose(FixedSizeMemoryPool* pool,NativeStackPool<List<K>>* stackPool)
         {
             if (_value!=null)
             {
-                pool->Return(_value);
+                if (!stackPool->IsPoolMax())
+                {
+                    stackPool->Return(_value);
+                    _value = null;
+                }
+                else
+                {
+                    _value->Dispose();
+                    pool->Free(_value);
+                }
             }
         }
     }

+ 9 - 3
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativePool.cs → Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativeStackPool.cs

@@ -9,13 +9,13 @@ namespace NativeCollection.UnsafeType
         public void OnGetFromPool();
     }
     
-    public unsafe struct NativePool<T> : IDisposable where T: unmanaged,IPool
+    public unsafe struct NativeStackPool<T> : IDisposable where T: unmanaged,IPool
     {
         public int MaxSize { get; private set; }
         private Stack<IntPtr>* _stack;
-        public static NativePool<T>* Create(int maxPoolSize)
+        public static NativeStackPool<T>* Create(int maxPoolSize)
         {
-            NativePool<T>* pool = (NativePool<T>*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<NativePool<T>>());
+            NativeStackPool<T>* pool = (NativeStackPool<T>*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<NativeStackPool<T>>());
             pool->_stack = Stack<IntPtr>.Create();
             pool->MaxSize = maxPoolSize;
             return pool;
@@ -46,6 +46,12 @@ namespace NativeCollection.UnsafeType
             ptr->OnReturnToPool();
             _stack->Push(new IntPtr(ptr));
         }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public bool IsPoolMax()
+        {
+            return _stack->Count >= MaxSize;
+        }
     
         public void Clear()
         {

+ 11 - 0
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/NativeStackPool.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e5c05c2ddcd32d949bf07233a92ee720
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 36 - 19
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/SortedSet/Node.cs

@@ -22,23 +22,46 @@ namespace NativeCollection.UnsafeType
     }
     internal struct Node : IEquatable<Node>, IPool
     {
-        public T Item;
-
-        public Node* Self;
-
-        public NodeColor Color;
-
         public Node* Left;
 
         public Node* Right;
+        
+        public NodeColor Color;
+        
+        public T Item;
+        
+        public Node* Self
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return (Node*)Unsafe.AsPointer(ref this); }
+        }
 
-        public bool IsBlack => Color == NodeColor.Black;
+        public bool IsBlack
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return Color == NodeColor.Black; }
+        }
 
-        public bool IsRed => Color == NodeColor.Red;
+        public bool IsRed
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return Color == NodeColor.Red; }
+        }
 
-        public bool Is2Node => IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right);
+        public bool Is2Node
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get { return IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right); }
+        }
 
-        public bool Is4Node => IsNonNullRed(Left) && IsNonNullRed(Right);
+        public bool Is4Node
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return IsNonNullRed(Left) && IsNonNullRed(Right);
+            }
+        }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void ColorBlack()
@@ -73,7 +96,6 @@ namespace NativeCollection.UnsafeType
         public static Node* Create(in T item, NodeColor nodeColor)
         {
             var node = (Node*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<Node>());
-            node->Self = node;
             node->Item = item;
             node->Color = nodeColor;
             node->Left = null;
@@ -82,14 +104,9 @@ namespace NativeCollection.UnsafeType
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Node* AllocFromPool(in T item, NodeColor nodeColor, NativePool<Node>* pool)
+        public static Node* AllocFromMemoryPool(in T item, NodeColor nodeColor, FixedSizeMemoryPool* memoryPool)
         {
-            var node = pool->Alloc();
-            if (node==null)
-            {
-                return Create(item, nodeColor);
-            }
-            node->Self = node;
+            Node* node = (Node*)memoryPool->Alloc();
             node->Item = item;
             node->Color = nodeColor;
             node->Left = null;
@@ -322,7 +339,7 @@ namespace NativeCollection.UnsafeType
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool Equals(Node other)
         {
-            return ((Object)Item).Equals(other.Item) && Self == other.Self && Color == other.Color && Left == other.Left &&
+            return (Item).Equals(other.Item) && Self == other.Self && Color == other.Color && Left == other.Left &&
                    Right == other.Right;
         }
 

+ 36 - 27
Unity/Assets/Scripts/ThirdParty/NativeCollection/UnsafeType/SortedSet/SortedSet.cs

@@ -13,26 +13,34 @@ namespace NativeCollection.UnsafeType
     private SortedSet<T>* _self;
     private int _count;
     private Node* _root;
-    private NativePool<Node>* _nodePool;
-    private NativePool<Stack<IntPtr>>* _stackPool;
+    private FixedSizeMemoryPool* _nodeMemoryPool;
+    private NativeStackPool<Stack<IntPtr>>* _stackPool;
     private int _version;
-    private const int _defaultNodePoolSize = 50;
-    public static SortedSet<T>* Create(int nodePoolSize = _defaultNodePoolSize)
+    private const int _defaultNodePoolBlockSize = 64;
+    public static SortedSet<T>* Create(int nodePoolBlockSize = _defaultNodePoolBlockSize)
     {
         var sortedSet = (SortedSet<T>*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf<SortedSet<T>>());
         sortedSet->_self = sortedSet;
         sortedSet->_root = null;
         sortedSet->_count = 0;
         sortedSet->_version = 0;
-        sortedSet->_nodePool = NativePool<Node>.Create(nodePoolSize);
-        sortedSet->_stackPool = NativePool<Stack<IntPtr>>.Create(2);
+        sortedSet->_stackPool = NativeStackPool<Stack<IntPtr>>.Create(2);
+        sortedSet->_nodeMemoryPool = FixedSizeMemoryPool.Create(nodePoolBlockSize, Unsafe.SizeOf<Node>());
         return sortedSet;
     }
 
-    public T? Min => MinInternal;
+    public T? Min
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        get
+        {
+            return MinInternal;
+        }
+    }
 
     internal T? MinInternal
     {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         get
         {
             if (_root == null) return default;
@@ -44,10 +52,15 @@ namespace NativeCollection.UnsafeType
         }
     }
 
-    public T? Max => MaxInternal;
+    public T? Max
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        get { return MaxInternal; }
+    }
 
     internal T? MaxInternal
     {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         get
         {
             if (_root == null) return default;
@@ -62,6 +75,7 @@ namespace NativeCollection.UnsafeType
 
     public int Count
     {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         get
         {
             VersionCheck(true);
@@ -98,24 +112,18 @@ namespace NativeCollection.UnsafeType
     public void Clear()
     {
         using var enumerator = GetEnumerator();
-        var nodeCount = 0;
         do
         {
             if (enumerator.CurrentPointer != null)
             {
-                NativeMemoryHelper.Free(enumerator.CurrentPointer);
-                NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<Node>());
-                nodeCount++;
+                _nodeMemoryPool->Free(enumerator.CurrentPointer);
+                
             }
         } while (enumerator.MoveNext());
-
-        if (nodeCount != 0) NativeMemoryHelper.RemoveNativeMemoryByte(nodeCount * Unsafe.SizeOf<Node>());
-
+        
         _root = null;
         _count = 0;
         ++_version;
-
-        _nodePool->Clear();
         _stackPool->Clear();
     }
 
@@ -144,17 +152,17 @@ namespace NativeCollection.UnsafeType
     public void Dispose()
     {
         Clear();
-        if (_nodePool!=null)
-        {
-            _nodePool->Dispose();
-            NativeMemoryHelper.Free(_nodePool);
-            NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<NativePool<Node>>());
-        }
         if (_stackPool!=null)
         {
             _stackPool->Dispose();
             NativeMemoryHelper.Free(_stackPool);
-            NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<NativePool<Stack<IntPtr>>>());
+            NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf<NativeStackPool<Stack<IntPtr>>>());
+        }
+
+        if (_nodeMemoryPool!=null)
+        {
+            _nodeMemoryPool->Dispose();
+            _nodeMemoryPool = null;
         }
         _version = 0;
     }
@@ -265,7 +273,7 @@ namespace NativeCollection.UnsafeType
         if (_root == null)
         {
             // The tree is empty and this is the first item.
-            _root = Node.AllocFromPool(item, NodeColor.Black,_nodePool);
+            _root = Node.AllocFromMemoryPool(item, NodeColor.Black,_nodeMemoryPool);
             _count = 1;
             _version++;
             return true;
@@ -311,7 +319,7 @@ namespace NativeCollection.UnsafeType
 
         Debug.Assert(parent != null);
         // We're ready to insert the new node.
-        var node = Node.AllocFromPool(item, NodeColor.Red,_nodePool);
+        var node = Node.AllocFromMemoryPool(item, NodeColor.Red,_nodeMemoryPool);
         if (order > 0)
             parent->Right = node;
         else
@@ -426,7 +434,8 @@ namespace NativeCollection.UnsafeType
         {
             ReplaceNode(match, parentOfMatch!, parent!, grandParent!);
             --_count;
-            _nodePool->Return(match);
+            //_nodePool->Return(match);
+            _nodeMemoryPool->Free(match);
         }
 
         if (_root != null) _root->ColorBlack();