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.总结

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

相关推荐
一只小小汤圆22 分钟前
如何xml序列化 和反序列化类中包含的类
xml·开发语言·c#
wkj0014 小时前
接口实现类向上转型和向上转型解析
java·开发语言·c#
徐子竣4 小时前
Unity性能优化-C#编码模块
unity·性能优化·游戏引擎
阿伍.6 小时前
【指针】(适合考研、专升本)
c++·考研·c#
Thomas_YXQ6 小时前
Unity3D SM节点式动画技能编辑器实现
开发语言·游戏·unity·编辑器·游戏引擎
香煎三文鱼6 小时前
C# net8生成excel,并设置列规则导出文件
c#·excel·c#生成ecel
汪小白JIY7 小时前
【C#】多级缓存与多核CPU
缓存·c#·多级缓存
心前阳光7 小时前
Unity-通过Transform类学习迭代器模式
学习·unity·迭代器模式
工程师0078 小时前
C#AES加密
网络·安全·web安全·c#