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

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

相关推荐
脑电信号要分类7 小时前
将多张图片拼接成一个pdf文件输出
pdf·c#·apache
njsgcs7 小时前
c# solidworks 折弯系数检查
开发语言·c#
格林威8 小时前
工业相机图像采集:Grab Timeout 设置建议——拒绝“假死”与“丢帧”的黄金法则
开发语言·人工智能·数码相机·计算机视觉·c#·机器视觉·工业相机
唐青枫9 小时前
C#.NET SignalR + Redis Backplane 深入解析:多节点部署与跨实例消息同步
c#·.net
努力长头发的程序猿11 小时前
在Unity2d中,根据Y轴决定渲染顺序(URP项目适用)
unity
DaLiangChen21 小时前
Unity 精准 Mesh 点击检测:穿透遮挡 + 单击双击识别
unity·游戏引擎
FL162386312921 小时前
[C#][winform]segment-anything分割万物部署onnx模型一键抠图演示
开发语言·c#
love530love1 天前
OpenClaw 手机直连配置全流程
人工智能·windows·python·智能手机·c#·agent·openclaw
迪普阳光开朗很健康1 天前
Unity中new() 和实例化有什么区别?
unity·游戏引擎
mxwin1 天前
Unity Shader 极坐标特效 从数学原理到实战案例
unity·游戏引擎·shader·uv