Просмотр исходного кода

这次彻底消除了所有GC,之前还剩下两个地方的每帧GC
1.TimerComponent有个MultiMap,里面是SortedDictionary,每帧要foreach,这会产生GC
2.KService同样有个MultiMap,也要产生GC
这次我写了一个有序的双向链表容器SortedCollection来代替SortedDictionary,虽然插入是个O(N)的算法,但是因为客户端的计时器并不多
KChannel也不多,所以效率是可以接受的,服务端GC不是问题,还是使用SortedDictionary。

目前状态同步demo已经完全没了每帧GC,移动过程中也没有了
测试方法,Unity右下角切换成Release,BuildEditor中选择Release,点击ReGenerateProjectFiles生成工程文件,IDE中编译dll,运行

tanghai 2 лет назад
Родитель
Сommit
e4a0840854

+ 7 - 11
Unity/Assets/Scripts/Core/Fiber/Module/Timer/TimerComponent.cs

@@ -77,20 +77,16 @@ namespace ET
                 return;
             }
 
-            using (var enumerator = self.timeId.GetEnumerator())
+            foreach (var kv in self.timeId)
             {
-                while (enumerator.MoveNext())
+                long k = kv.Key;
+                if (k > timeNow)
                 {
-                    var kv = enumerator.Current;
-                    long k = kv.Key;
-                    if (k > timeNow)
-                    {
-                        self.minTime = k;
-                        break;
-                    }
-
-                    self.timeOutTime.Enqueue(k);
+                    self.minTime = k;
+                    break;
                 }
+
+                self.timeOutTime.Enqueue(k);
             }
 
             while (self.timeOutTime.Count > 0)

+ 1 - 6
Unity/Assets/Scripts/Core/MultiMap.cs

@@ -3,12 +3,7 @@ using System.Collections.Generic;
 
 namespace ET
 {
-    public class MultiMap<T, K>:
-//#if UNITY
-//            SortedLinkList<T, List<K>>
-//#else
-            SortedDictionary<T, List<K>>
-//#endif
+    public class MultiMap<T, K>: SortedCollection<T, List<K>>
     {
         private readonly List<K> Empty = new();
         private readonly int maxPoolCount;

+ 3 - 35
Unity/Assets/Scripts/Core/Network/KService.cs

@@ -92,7 +92,7 @@ namespace ET
 
         private readonly List<long> cacheIds = new List<long>();
         
-#if !UNITY
+
         // 下帧要更新的channel
         private readonly HashSet<long> updateIds = new HashSet<long>();
         // 下次时间更新的channel
@@ -100,7 +100,8 @@ namespace ET
         private readonly List<long> timeOutTime = new List<long>();
         // 记录最小时间,不用每次都去MultiMap取第一个值
         private long minTime;
-        
+
+#if !UNITY
         public readonly ArrayPool<byte> byteArrayPool = ArrayPool<byte>.Create(2048,3000);
 #else
         public readonly ArrayPool<byte> byteArrayPool = ArrayPool<byte>.Create(2048,200);
@@ -526,34 +527,6 @@ namespace ET
 
         private void UpdateChannel(uint timeNow)
         {
-#if UNITY
-            // Unity中,每帧更新Channel
-            this.cacheIds.Clear();
-            foreach (var kv in this.waitAcceptChannels)
-            {
-                this.cacheIds.Add(kv.Key);
-            }
-            foreach (var kv in this.localConnChannels)
-            {
-                this.cacheIds.Add(kv.Key);
-            }
-
-            foreach (long id in this.cacheIds)
-            {
-                KChannel kChannel = this.Get(id);
-                if (kChannel == null)
-                {
-                    continue;
-                }
-
-                if (kChannel.Id == 0)
-                {
-                    continue;
-                }
-                kChannel.Update(timeNow);
-            }
-            
-#else
             foreach (long id in this.updateIds)
             {
                 KChannel kChannel = this.Get(id);
@@ -570,13 +543,11 @@ namespace ET
                 kChannel.Update(timeNow);
             }
             this.updateIds.Clear();
-#endif
         }
         
         // 服务端需要看channel的update时间是否已到
         public void AddToUpdate(long time, long id)
         {
-#if !UNITY
             if (time == 0)
             {
                 this.updateIds.Add(id);
@@ -587,14 +558,12 @@ namespace ET
                 this.minTime = time;
             }
             this.timeId.Add(time, id);
-#endif
         }
         
 
         // 计算到期需要update的channel
         private void TimerOut(uint timeNow)
         {
-#if !UNITY
             if (this.timeId.Count == 0)
             {
                 return;
@@ -628,7 +597,6 @@ namespace ET
                 }
                 this.timeId.Remove(k);
             }
-#endif
         }
     }
 }

+ 248 - 0
Unity/Assets/Scripts/Core/SortedCollection.cs

@@ -0,0 +1,248 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace ET
+{
+#if DOTNET
+    public class SortedCollection<K, V>: SortedDictionary<K, V>
+    {
+    }
+    
+#else
+    public class SortedCollection<K, V>: IEnumerable<KeyValuePair<K, V>>
+    {
+        private class Enumerator: IEnumerator<KeyValuePair<K, V>>
+        {
+            private readonly SortedCollection<K, V> sortedCollection;
+            private Node current;
+            private int index;
+
+            public Enumerator(SortedCollection<K, V> sortedCollection)
+            {
+                this.sortedCollection = sortedCollection;
+                this.index = 0;
+                this.current = null;
+            }
+            
+            public void Dispose()
+            {
+                // TODO release managed resources here
+            }
+
+            public bool MoveNext()
+            {
+                if (++this.index > this.sortedCollection.dict.Count)
+                {
+                    return false;
+                }
+                if (this.current == null)
+                {
+                    this.current = this.sortedCollection.head;
+                    return true;
+                }
+                if (this.current.Next == null)
+                {
+                    return false;
+                }
+                this.current = this.current.Next;
+                return true;
+            }
+
+            public void Reset()
+            {
+                this.index = 0;
+                this.current = null;
+            }
+
+            public KeyValuePair<K, V> Current
+            {
+                get
+                {
+                    return new KeyValuePair<K, V>(this.current.Key, this.current.Value);
+                }
+            }
+
+            object IEnumerator.Current => this.Current;
+        }
+        
+        public class Node
+        {
+            internal Node Next;
+            internal Node Pre;
+            public K Key;
+            public V Value;
+        }
+
+        private readonly IComparer<K> comparer;
+
+        private readonly Dictionary<K, Node> dict = new();
+        
+        private readonly Queue<Node> pool = new();
+
+        private Node head;
+
+        private readonly Enumerator enumerator;
+
+        public SortedCollection()
+        {
+            this.comparer = Comparer<K>.Default;
+            this.enumerator = new Enumerator(this);
+        }
+        
+        public SortedCollection(IComparer<K> comparer)
+        {
+            this.comparer = comparer ?? Comparer<K>.Default;
+            this.enumerator = new Enumerator(this);
+        }
+
+        private Node Fetch()
+        {
+            if (this.pool.Count == 0)
+            {
+                return new Node();
+            }
+            return this.pool.Dequeue();
+        }
+        
+        private void Recycle(Node node)
+        {
+            node.Next = null;
+            node.Pre = null;
+            node.Key = default;
+            node.Value = default;
+            if (this.pool.Count > 1000)
+            {
+                return;
+            }
+            this.pool.Enqueue(node);
+        }
+
+        public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
+        {
+            this.enumerator.Reset();
+            return this.enumerator;
+        }
+
+        public void Add(K k, V v)
+        {
+            Node node = this.Fetch();
+            node.Key = k;
+            node.Value = v;
+            this.dict.Add(k, node);
+            
+            if (this.head == null)
+            {
+                this.head = node;
+                return;
+            }
+            
+            Node p = this.head;
+            if (comparer.Compare(k, p.Key) < 0)
+            {
+                node.Next = p;
+                p.Pre = node;
+                this.head = node;
+                return;
+            }
+
+            Node q = p.Next;
+            while (true)
+            {
+                if (q == null) // 到末尾
+                {
+                    p.Next = node;
+                    node.Pre = p;
+                    break;
+                }
+                
+                int ret = comparer.Compare(k, q.Key);
+
+                if (ret == 0)
+                {
+                    break;
+                }
+                
+                if (ret < 0)
+                {
+                    node.Next = q;
+                    q.Pre = node;
+                    p.Next = node;
+                    node.Pre = p;
+                    break;
+                }
+                
+                p = p.Next;
+                q = q.Next;
+            }
+        }
+
+        public bool Remove(K k)
+        {
+            if (!this.dict.Remove(k, out Node node))
+            {
+                return false;
+            }
+
+            if (this.dict.Count == 0)
+            {
+                this.head = null;
+                this.Recycle(node);
+                return true;
+            }
+
+            if (node.Pre == null)
+            {
+                node.Next.Pre = null;
+                this.head = node.Next;
+                this.Recycle(node);
+                return true;
+            }
+
+            if (node.Next == null)
+            {
+                node.Pre.Next = null;
+                this.Recycle(node);
+                return true;
+            }
+
+            node.Pre.Next = node.Next;
+            node.Next.Pre = node.Pre;
+            this.Recycle(node);
+            return true;
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return this.GetEnumerator();
+        }
+
+        public V this[K k]
+        {
+            get
+            {
+                return this.dict[k].Value;
+            }
+            set
+            {
+                this.Remove(k);
+                this.Add(k, value);
+            }
+        }
+
+        public bool TryGetValue(K k, out V v)
+        {
+            bool ret = this.dict.TryGetValue(k, out Node node);
+            v = ret? node.Value : default;
+            return ret;
+        }
+
+        public int Count
+        {
+            get
+            {
+                return this.dict.Count;
+            }
+        }
+    }
+#endif
+}

+ 1 - 1
Unity/Assets/Scripts/Core/SortedLinkList.cs.meta → Unity/Assets/Scripts/Core/SortedCollection.cs.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ae9d7cf85779e447f9e10e80ad618d49
+guid: bd1f98dab4bd9a34e8da9bea5823fab7
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2

+ 0 - 143
Unity/Assets/Scripts/Core/SortedLinkList.cs

@@ -1,143 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-namespace ET
-{
-    public class SortedLinkList<T, K>: Dictionary<T, K> where T: IComparable<T>, IEnumerable
-    {
-        //public struct KeyValuePair
-        //{
-        //    public SortedLinkList<T, K> sortedLinkList;
-        //    public T Key;
-        //    public K Value;
-        //    
-        //    public KeyValuePair()
-        //}
-        
-        public class Node
-        {
-            public Node Next;
-            public T Value;
-        }
-
-        private readonly Queue<Node> pool = new();
-
-        private Node head;
-
-        private Node Fetch()
-        {
-            if (this.pool.Count == 0)
-            {
-                return new Node();    
-            }
-            return this.pool.Dequeue();
-        }
-        
-        private void Recycle(Node node)
-        {
-            node.Next = null;
-            node.Value = default;
-            if (this.pool.Count > 1000)
-            {
-                return;
-            }
-            this.pool.Enqueue(node);
-        }
-
-        //public new KeyValuePair GetEnumerator()
-        //{
-        //    return new 
-        //}
-
-        public T FirstKey()
-        {
-            return this.head.Value;
-        }
-
-        public new void Add(T t, K k)
-        {
-            if (this.head == null)
-            {
-                Node node = this.Fetch();
-                node.Value = t;
-                this.head = node;
-                return;
-            }
-            if (t.CompareTo(this.head.Value) < 0)
-            {
-                Node node = this.Fetch();
-                node.Value = t;
-                node.Next = this.head;
-                this.head = node;
-                base.Add(t, k);
-                return;
-            }
-
-            Node p = this.head;
-            while (true)
-            {
-                Node node = null;
-                if (p.Next == null)
-                {
-                    node = this.Fetch();
-                    node.Value = t;
-                    p.Next = node;
-                    break;
-                }
-                
-                int ret = t.CompareTo(p.Next.Value);
-
-                if (ret == 0)
-                {
-                    break;
-                }
-                
-                if (ret > 0)
-                {
-                    p = p.Next;
-                    continue;
-                }
-
-                node = this.Fetch();
-                node.Value = t;
-                node.Next = p.Next;
-                p.Next = node;
-            }
-            base.Add(t, k);
-        }
-
-        public new bool Remove(T t)
-        {
-            if (this.head == null)
-            {
-                return false;
-            }
-            
-            Node p = this.head;
-            
-            while (true)
-            {
-                if (p.Next == null)
-                {
-                    break;
-                }
-                
-                int ret = t.CompareTo(p.Next.Value);
-
-                if (ret == 0)
-                {
-                    this.Recycle(p.Next);
-                    p.Next = p.Next.Next;
-                    break;
-                }
-                
-                if (ret > 0)
-                {
-                    p = p.Next;
-                }
-            }
-            return base.Remove(t);
-        }
-    }
-}

+ 3 - 1
Unity/Assets/Scripts/Model/Share/Entry.cs

@@ -1,4 +1,6 @@
-namespace ET
+using System.Collections.Generic;
+
+namespace ET
 {
     public struct EntryEvent1
     {