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.总结
重复使用的对象只创建有限次,避免来回实例化对象的开销