Unity C# 引用池 ReferencePool

Unity C# 引用池 ReferencePool

1.目的

对于多次创建的数据使用new 关键字是十分消耗性能的,使用完成后由GC去自动释放,当一个类型的数据频繁创建可以使用引用池进行管理。

2.实现

项目目录

IReference 接口

要放入引用池的数据只需要继承这个接口即可

csharp 复制代码
namespace ReferencePool
{
    public interface IReference
    {
        void Clear();
    }
}

ReferenceCollection 引用集合

一个类型对应一个引用集合,每次请求从引用集合的队列中获取

csharp 复制代码
namespace ReferencePool
{
    public class ReferenceCollection
    {
        private readonly Queue<IReference> m_References = new Queue<IReference>();
        private Type m_ReferenceType;
        private int m_CurrUsingRefCount;//当前引用的数量
        private int m_AcquireRefCount;//请求引用的总数量
        private int m_ReleaseRefCount;//释放引用的总数量
        private int m_AddRefCount;//添加引用的总数量
        private int m_RemoveRefCount;//移除引用的总数量

        public int CurrUsingRefCount => m_CurrUsingRefCount;
        public int AcquireRefCount => m_AcquireRefCount;
        public int ReleaseRefCount => m_ReleaseRefCount;
        public int AddRefCount => m_AddRefCount;
        public int RemoveRefCount => m_RemoveRefCount;


        public ReferenceCollection(Type refType)
        {
            m_ReferenceType = refType;
            m_CurrUsingRefCount = 0;
            m_AcquireRefCount = 0;
            m_ReleaseRefCount = 0;
            m_AddRefCount = 0;
            m_RemoveRefCount = 0;
        }

        public T Acquire<T>() where T : class, IReference, new()
        {
            if (typeof(T) != m_ReferenceType)
            {
                throw new Exception("类型不相同无法请求!!!");
            }
            m_CurrUsingRefCount++;
            m_AcquireRefCount++;
            lock (m_References)
            {
                if (m_References.Count > 0)
                {
                    return (T)m_References.Dequeue();
                }
            }
            m_AddRefCount++;
            return new T();
        }

        public void Release(IReference reference)
        {
            reference.Clear();
            lock (m_References)
            {
                if (m_References.Contains(reference))
                {
                    throw new Exception("引用已经被释放,请勿重新释放!!!");
                }

                m_References.Enqueue(reference);
            }

            m_CurrUsingRefCount--;
            m_ReleaseRefCount++;
        }

        public void Add<T>(int count) where T : class, IReference, new()
        {
            if (typeof(T) != m_ReferenceType)
            {
                throw new Exception("类型不相同无法添加!!!");
            }
            lock (m_References)
            {
                m_AddRefCount += count;
                while (count-- > 0)
                {
                    m_References.Enqueue(new T());
                }
            }
        }

        public void Remove(int count)
        {
            lock (m_References)
            {
                if(count > m_References.Count)
                {
                    count = m_References.Count;
                }
                m_RemoveRefCount += count;
                while (count-- > 0)
                {
                    m_References.Dequeue();
                }
            }
        }

        public void RemoveAll()
        {
            lock (m_References)
            {
                m_RemoveRefCount += m_References.Count;
                m_References.Clear();
            }
        }
    }
}

ReferencePool 真正的引用池

对引用集合进行统一管理

csharp 复制代码
public static class ReferencePool
    {
        private static readonly Dictionary<Type,ReferenceCollection> m_ReferenceCollections = new Dictionary<Type,ReferenceCollection>();
        public static int Count => m_ReferenceCollections.Count;//获取引用池的数量
        public static void ClearAll()
        {
            lock (m_ReferenceCollections)
            {
                foreach (var reference in m_ReferenceCollections.Values)
                {
                    reference.RemoveAll();
                }
                m_ReferenceCollections.Clear();
            }
        }

        public static T Acquire<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).Acquire<T>();
        }

        public static void Release(IReference reference)
        {
            GetReferenceCollection(reference.GetType()).Release(reference);
        }

        public static void Add<T>(int count) where T : class, IReference, new()
        {
            GetReferenceCollection(typeof(T)).Add<T>(count);
        }

        public static void Remove<T>(int count) where T : class, IReference, new()
        {
            GetReferenceCollection(typeof(T)).Remove(count);
        }

        public static void RemoveAll<T>() where T : class, IReference, new()
        {
            GetReferenceCollection(typeof(T)).RemoveAll();
        }

        private static ReferenceCollection GetReferenceCollection(Type type)
        {
            if (type == null)
            {
                throw new Exception("Type 类型 为空!!!");
            }
            ReferenceCollection referenceCollection = null;
            lock (m_ReferenceCollections)
            {
                if(!m_ReferenceCollections.TryGetValue(type,out referenceCollection))
                {
                    referenceCollection = new ReferenceCollection(type);
                    m_ReferenceCollections.Add(type, referenceCollection);
                }
            }
            return referenceCollection;
        }

        public static int GetCurrUsingRefCount<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).CurrUsingRefCount;
        }
        public static int GetAcquireRefCount<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).AcquireRefCount;
        }
        public static int GetReleaseRefCount<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).ReleaseRefCount;
        }
        public static int GetAddRefCount<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).AddRefCount;
        }
        public static int GetRemoveRefCount<T>() where T : class, IReference, new()
        {
            return GetReferenceCollection(typeof(T)).RemoveRefCount;
        }
    }

3.测试

csharp 复制代码
namespace ReferencePool
{
    public class Program
    {
        static void Main(string[] args)
        {
            TeacherData teacherData1 = ReferencePool.Acquire<TeacherData>();
            teacherData1.Name = "zzs";
            teacherData1.Age = 20;
            ReferencePool.Release(teacherData1);
            TeacherData teacherData2 = ReferencePool.Acquire<TeacherData>();
            teacherData1.Name = "xxx";
            teacherData1.Age = 18;

            Console.WriteLine(ReferencePool.GetCurrUsingRefCount<TeacherData>());
            Console.WriteLine(ReferencePool.GetAcquireRefCount<TeacherData>());
            Console.WriteLine(ReferencePool.GetReleaseRefCount<TeacherData>());
            Console.WriteLine(ReferencePool.GetAddRefCount<TeacherData>());
            Console.WriteLine(ReferencePool.GetRemoveRefCount<TeacherData>());
            Console.ReadKey();
        }
    }

    public class TeacherData : IReference
    {
        public string Name;
        public int Age;
        public void Clear()
        {
            Name = string.Empty;
            Age = 0;
        }
    }
}

4.总结

重复使用的对象只创建有限次,避免来回实例化对象的开销

相关推荐
喵叔哟4 分钟前
06-ASPNETCore-WebAPI开发
服务器·后端·c#
天人合一peng18 分钟前
unity 通过代码修改button及其名字字体的属性
unity·游戏引擎
2501_9307077823 分钟前
使用 C# .NET 从 PowerPoint 演示文稿中提取背景图片
c#·powerpoint·.net
初级代码游戏1 小时前
套路化编程 C# winform 自适应缩放布局
开发语言·c#·winform·自动布局·自动缩放
大空大地20262 小时前
流程控制语句--switch多分支语句使用、while循环语句的使用、do...while语句、for循环
c#
kylezhao20194 小时前
C#序列化与反序列化详细讲解与应用
c#
JQLvopkk4 小时前
C# 实践AI :Visual Studio + VSCode 组合方案
人工智能·c#·visual studio
故事不长丨4 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
kingwebo'sZone4 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
GLDbalala4 小时前
Unity基于自定义管线实现经典经验光照模型
unity·游戏引擎