167 lines
5.2 KiB
C#
167 lines
5.2 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Runtime.CompilerServices;
|
||
|
||
namespace AlicizaX
|
||
{
|
||
/// <summary>
|
||
/// 内存池注册表。非泛型路径通过此表查找对应的泛型池。
|
||
/// 注册发生在 MemoryPool<T> 静态构造器中,仅一次。
|
||
/// </summary>
|
||
public static class MemoryPoolRegistry
|
||
{
|
||
internal sealed class MemoryPoolHandle
|
||
{
|
||
public readonly Func<IMemory> Acquire;
|
||
public readonly Action<IMemory> Release;
|
||
public readonly Action Clear;
|
||
public readonly Action<int> Prewarm;
|
||
public readonly Func<MemoryPoolInfo> GetInfo;
|
||
public readonly Action<int> Tick;
|
||
public readonly Action<int> Shrink;
|
||
|
||
public MemoryPoolHandle(
|
||
Func<IMemory> acquire,
|
||
Action<IMemory> release,
|
||
Action clear,
|
||
Action<int> prewarm,
|
||
Func<MemoryPoolInfo> getInfo,
|
||
Action<int> tick,
|
||
Action<int> shrink)
|
||
{
|
||
Acquire = acquire;
|
||
Release = release;
|
||
Clear = clear;
|
||
Prewarm = prewarm;
|
||
GetInfo = getInfo;
|
||
Tick = tick;
|
||
Shrink = shrink;
|
||
}
|
||
}
|
||
|
||
private static readonly Dictionary<Type, MemoryPoolHandle> s_Handles
|
||
= new Dictionary<Type, MemoryPoolHandle>(64);
|
||
|
||
// Tick 回调用数组缓存,避免每帧遍历 Dictionary
|
||
private static Action<int>[] s_TickArray = Array.Empty<Action<int>>();
|
||
private static int s_TickCount;
|
||
private static bool s_TickArrayDirty;
|
||
|
||
public static int Count => s_Handles.Count;
|
||
|
||
internal static void Register(Type type, MemoryPoolHandle handle)
|
||
{
|
||
s_Handles[type] = handle;
|
||
s_TickArrayDirty = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 非泛型 Acquire,用于只有 Type 没有泛型参数的场景。
|
||
/// </summary>
|
||
public static IMemory Acquire(Type type)
|
||
{
|
||
if (s_Handles.TryGetValue(type, out var handle))
|
||
return handle.Acquire();
|
||
|
||
// 首次访问:触发 MemoryPool<T> 静态构造器
|
||
RuntimeHelpers.RunClassConstructor(
|
||
typeof(MemoryPool<>).MakeGenericType(type).TypeHandle);
|
||
|
||
if (s_Handles.TryGetValue(type, out handle))
|
||
return handle.Acquire();
|
||
|
||
throw new Exception($"MemoryPool: Type '{type.FullName}' is not a valid IMemory type.");
|
||
}
|
||
|
||
public static void Release(IMemory memory)
|
||
{
|
||
if (memory == null)
|
||
throw new ArgumentNullException(nameof(memory));
|
||
|
||
Type type = memory.GetType();
|
||
if (s_Handles.TryGetValue(type, out var handle))
|
||
{
|
||
handle.Release(memory);
|
||
return;
|
||
}
|
||
|
||
// 首次访问:触发静态构造器
|
||
RuntimeHelpers.RunClassConstructor(
|
||
typeof(MemoryPool<>).MakeGenericType(type).TypeHandle);
|
||
|
||
if (s_Handles.TryGetValue(type, out handle))
|
||
handle.Release(memory);
|
||
}
|
||
|
||
public static MemoryPoolInfo[] GetAllInfos()
|
||
{
|
||
var infos = new MemoryPoolInfo[s_Handles.Count];
|
||
int i = 0;
|
||
foreach (var kv in s_Handles)
|
||
infos[i++] = kv.Value.GetInfo();
|
||
return infos;
|
||
}
|
||
|
||
public static void ClearAll()
|
||
{
|
||
foreach (var kv in s_Handles)
|
||
kv.Value.Clear();
|
||
}
|
||
|
||
public static void Prewarm(Type type, int count)
|
||
{
|
||
if (s_Handles.TryGetValue(type, out var handle))
|
||
{
|
||
handle.Prewarm(count);
|
||
return;
|
||
}
|
||
|
||
RuntimeHelpers.RunClassConstructor(
|
||
typeof(MemoryPool<>).MakeGenericType(type).TypeHandle);
|
||
|
||
if (s_Handles.TryGetValue(type, out handle))
|
||
handle.Prewarm(count);
|
||
}
|
||
|
||
public static void ClearType(Type type)
|
||
{
|
||
if (s_Handles.TryGetValue(type, out var handle))
|
||
handle.Clear();
|
||
}
|
||
|
||
public static void RemoveFromType(Type type, int count)
|
||
{
|
||
if (s_Handles.TryGetValue(type, out var handle))
|
||
{
|
||
int unused = handle.GetInfo().UnusedCount;
|
||
handle.Shrink(unused - count);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 每帧由 MemoryPoolTicker 调用,驱动所有池的自动回收。
|
||
/// </summary>
|
||
public static void TickAll(int frameCount)
|
||
{
|
||
if (s_TickArrayDirty)
|
||
RebuildTickArray();
|
||
|
||
for (int i = 0; i < s_TickCount; i++)
|
||
s_TickArray[i](frameCount);
|
||
}
|
||
|
||
private static void RebuildTickArray()
|
||
{
|
||
s_TickCount = s_Handles.Count;
|
||
if (s_TickArray.Length < s_TickCount)
|
||
s_TickArray = new Action<int>[s_TickCount];
|
||
|
||
int i = 0;
|
||
foreach (var kv in s_Handles)
|
||
s_TickArray[i++] = kv.Value.Tick;
|
||
|
||
s_TickArrayDirty = false;
|
||
}
|
||
}
|
||
}
|