mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-17 17:34:36 +08:00
add MemoryAllocator/fix leaks
This commit is contained in:
parent
73bb779a5a
commit
3dde27a1e5
@ -1,6 +1,7 @@
|
|||||||
#if DISABLE_DEBUG
|
#if DISABLE_DEBUG
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
using DCFApixels.DragonECS.Core.Internal;
|
||||||
using DCFApixels.DragonECS.Core.Unchecked;
|
using DCFApixels.DragonECS.Core.Unchecked;
|
||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
using System;
|
using System;
|
||||||
@ -188,7 +189,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
||||||
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
||||||
|
|
||||||
private int*[] _groupSparsePagePool = new int*[64];
|
private MemoryAllocator.Handler[] _groupSparsePagePool = new MemoryAllocator.Handler[64];
|
||||||
private int _groupSparsePagePoolCount = 0;
|
private int _groupSparsePagePoolCount = 0;
|
||||||
|
|
||||||
#region Pages
|
#region Pages
|
||||||
@ -196,35 +197,44 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
if (_groupSparsePagePoolCount <= 0)
|
if (_groupSparsePagePoolCount <= 0)
|
||||||
{
|
{
|
||||||
var newPage = UnmanagedArrayUtility.NewAndInit<int>(EcsGroup.PAGE_SIZE);
|
return MemoryAllocator.AllocAndInit<int>(EcsGroup.PAGE_SIZE).As<int>();
|
||||||
return newPage;
|
|
||||||
}
|
}
|
||||||
var takedPage = _groupSparsePagePool[--_groupSparsePagePoolCount];
|
var takedPage = _groupSparsePagePool[--_groupSparsePagePoolCount];
|
||||||
_groupSparsePagePool[_groupSparsePagePoolCount] = null;
|
_groupSparsePagePool[_groupSparsePagePoolCount] = MemoryAllocator.Handler.Empty;
|
||||||
return takedPage;
|
return takedPage.As<int>();
|
||||||
}
|
}
|
||||||
internal void ReturnPage(int* page)
|
internal void ReturnPage(int* page)
|
||||||
{
|
{
|
||||||
|
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||||
|
var h = MemoryAllocator.Handler.FromDataPtr(page);
|
||||||
|
if (h.GetID() == 0 || page == null)
|
||||||
|
{
|
||||||
|
Throw.DeepDebugException();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length)
|
if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length)
|
||||||
{
|
{
|
||||||
var old = _groupSparsePagePool;
|
var old = _groupSparsePagePool;
|
||||||
_groupSparsePagePool = new int*[_groupSparsePagePoolCount << 1];
|
_groupSparsePagePool = new MemoryAllocator.Handler[_groupSparsePagePoolCount << 1];
|
||||||
for (int j = 0; j < old.Length; j++)
|
for (int j = 0; j < old.Length; j++)
|
||||||
{
|
{
|
||||||
_groupSparsePagePool[j] = old[j];
|
_groupSparsePagePool[j] = old[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_groupSparsePagePool[_groupSparsePagePoolCount++] = page;
|
_groupSparsePagePool[_groupSparsePagePoolCount++] = MemoryAllocator.Handler.FromDataPtr(page);
|
||||||
}
|
}
|
||||||
private void DisposeGroupPages()
|
private void DisposeGroups()
|
||||||
{
|
{
|
||||||
foreach (var page in _groupSparsePagePool)
|
for (int i = 0; i < _groupSparsePagePoolCount; i++)
|
||||||
{
|
{
|
||||||
if (page != null)
|
ref var page = ref _groupSparsePagePool[i];
|
||||||
|
if (page.IsEmpty == false)
|
||||||
{
|
{
|
||||||
UnmanagedArrayUtility.Free(page);
|
MemoryAllocator.Free(ref page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_groupSparsePagePoolCount = 0;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -277,12 +287,13 @@ namespace DCFApixels.DragonECS
|
|||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
private int[] _dense; // 0 индекс для нулевой записи
|
private int[] _dense; // 0 индекс для нулевой записи
|
||||||
private PageSlot* _sparsePages; //Старший бит занят временной маркировкой в операциях над множествами
|
private PageSlot* _sparsePages; //Старший бит занят временной маркировкой в операциях над множествами
|
||||||
|
private MemoryAllocator.Handler _sparsePagesHandler; //Старший бит занят временной маркировкой в операциях над множествами
|
||||||
private int _sparsePagesCount;
|
private int _sparsePagesCount;
|
||||||
private int _totalCapacity;
|
private int _totalCapacity;
|
||||||
private int _count = 0;
|
private int _count = 0;
|
||||||
internal bool _isReleased = true;
|
internal bool _isReleased = true;
|
||||||
|
|
||||||
internal static readonly int* _nullPage = UnmanagedArrayUtility.NewAndInit<int>(PageSlot.SIZE);
|
internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit<int>(PageSlot.SIZE).As<int>();
|
||||||
internal static readonly long _nullPagePtrFake = (long)_nullPage;
|
internal static readonly long _nullPagePtrFake = (long)_nullPage;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
@ -362,12 +373,31 @@ namespace DCFApixels.DragonECS
|
|||||||
_dense = new int[denseCapacity];
|
_dense = new int[denseCapacity];
|
||||||
_totalCapacity = world.Capacity;
|
_totalCapacity = world.Capacity;
|
||||||
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
||||||
_sparsePages = UnmanagedArrayUtility.New<PageSlot>(_sparsePagesCount);
|
_sparsePagesHandler = MemoryAllocator.Alloc<PageSlot>(_sparsePagesCount);
|
||||||
|
_sparsePages = _sparsePagesHandler.As<PageSlot>();
|
||||||
for (int i = 0; i < _sparsePagesCount; i++)
|
for (int i = 0; i < _sparsePagesCount; i++)
|
||||||
{
|
{
|
||||||
_sparsePages[i] = PageSlot.Empty;
|
_sparsePages[i] = PageSlot.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
~EcsGroup()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _sparsePagesCount; i++)
|
||||||
|
{
|
||||||
|
ref PageSlot page = ref _sparsePages[i];
|
||||||
|
if (page.Indexes != _nullPage)
|
||||||
|
{
|
||||||
|
MemoryAllocator.Free(page.Indexes);
|
||||||
|
page = default;
|
||||||
|
page.Indexes = _nullPage;
|
||||||
|
}
|
||||||
|
page.IndexesXOR = 0;
|
||||||
|
page.Count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_source.ReleaseGroup(this);
|
_source.ReleaseGroup(this);
|
||||||
@ -518,6 +548,9 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
if (_count == 0) { return; }
|
if (_count == 0) { return; }
|
||||||
|
|
||||||
|
if (_source.IsDestroyed == false)
|
||||||
|
{
|
||||||
for (int i = 0; i < _sparsePagesCount; i++)
|
for (int i = 0; i < _sparsePagesCount; i++)
|
||||||
{
|
{
|
||||||
ref PageSlot page = ref _sparsePages[i];
|
ref PageSlot page = ref _sparsePages[i];
|
||||||
@ -534,9 +567,9 @@ namespace DCFApixels.DragonECS
|
|||||||
page.IndexesXOR = 0;
|
page.IndexesXOR = 0;
|
||||||
page.Count = 0;
|
page.Count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Upsize
|
#region Upsize
|
||||||
@ -1550,7 +1583,9 @@ namespace DCFApixels.DragonECS
|
|||||||
_totalCapacity = newSize;
|
_totalCapacity = newSize;
|
||||||
var oldPagesCount = _sparsePagesCount;
|
var oldPagesCount = _sparsePagesCount;
|
||||||
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
||||||
_sparsePages = UnmanagedArrayUtility.Resize<PageSlot>(_sparsePages, _sparsePagesCount);
|
_sparsePagesHandler = MemoryAllocator.Realloc<PageSlot>(_sparsePagesHandler, _sparsePagesCount);
|
||||||
|
_sparsePages = _sparsePagesHandler.As<PageSlot>();
|
||||||
|
//_sparsePages = UnmanagedArrayUtility.Resize<PageSlot>(_sparsePages, _sparsePagesCount);
|
||||||
for (int i = oldPagesCount; i < _sparsePagesCount; i++)
|
for (int i = oldPagesCount; i < _sparsePagesCount; i++)
|
||||||
{
|
{
|
||||||
_sparsePages[i] = PageSlot.Empty;
|
_sparsePages[i] = PageSlot.Empty;
|
||||||
@ -1634,14 +1669,14 @@ namespace DCFApixels.DragonECS
|
|||||||
private PageSlot _page;
|
private PageSlot _page;
|
||||||
public int[] Indexes;
|
public int[] Indexes;
|
||||||
public IntPtr IndexesPtr;
|
public IntPtr IndexesPtr;
|
||||||
public bool IsNullPage
|
public bool IsNullPage;
|
||||||
{
|
|
||||||
get { return IndexesPtr == (IntPtr)_nullPagePtrFake; }
|
|
||||||
}
|
|
||||||
public int IndexesXOR;
|
public int IndexesXOR;
|
||||||
public sbyte Count;
|
public sbyte Count;
|
||||||
|
|
||||||
public DebuggerProxy(PageSlot page)
|
public DebuggerProxy(PageSlot page)
|
||||||
|
{
|
||||||
|
//if (page.Indexes == null) { return; }
|
||||||
|
//try
|
||||||
{
|
{
|
||||||
_page = page;
|
_page = page;
|
||||||
Indexes = new int[SIZE];
|
Indexes = new int[SIZE];
|
||||||
@ -1652,6 +1687,17 @@ namespace DCFApixels.DragonECS
|
|||||||
IndexesPtr = (IntPtr)page.Indexes;
|
IndexesPtr = (IntPtr)page.Indexes;
|
||||||
IndexesXOR = page.IndexesXOR;
|
IndexesXOR = page.IndexesXOR;
|
||||||
Count = page.Count;
|
Count = page.Count;
|
||||||
|
IsNullPage = IndexesPtr == (IntPtr)_nullPagePtrFake;
|
||||||
|
}
|
||||||
|
//catch (Exception)
|
||||||
|
//{
|
||||||
|
// _page = default;
|
||||||
|
// Indexes = null;
|
||||||
|
// IndexesPtr = default;
|
||||||
|
// IndexesXOR = default;
|
||||||
|
// Count = default;
|
||||||
|
// IsNullPage = default;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
#endif
|
#endif
|
||||||
using DCFApixels.DragonECS.Core;
|
using DCFApixels.DragonECS.Core;
|
||||||
|
using DCFApixels.DragonECS.Core.Internal;
|
||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -505,6 +506,9 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary> slised _sortIncChunckBuffer </summary>
|
/// <summary> slised _sortIncChunckBuffer </summary>
|
||||||
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
||||||
|
|
||||||
|
private MemoryAllocator.Handler _bufferHandler;
|
||||||
|
private MemoryAllocator.Handler _chunckBufferHandler;
|
||||||
|
|
||||||
private readonly bool _isSingleIncPoolWithEntityStorage;
|
private readonly bool _isSingleIncPoolWithEntityStorage;
|
||||||
private readonly bool _isHasAnyEntityStorage;
|
private readonly bool _isHasAnyEntityStorage;
|
||||||
private readonly MaskType _maskType;
|
private readonly MaskType _maskType;
|
||||||
@ -522,14 +526,21 @@ namespace DCFApixels.DragonECS
|
|||||||
World = source;
|
World = source;
|
||||||
Mask = mask;
|
Mask = mask;
|
||||||
|
|
||||||
var sortBuffer = new UnsafeArray<int>(mask._incs.Length + mask._excs.Length);
|
int bufferLength = mask._incs.Length + mask._excs.Length;
|
||||||
var sortChunckBuffer = new UnsafeArray<EcsMaskChunck>(mask._incChunckMasks.Length + mask._excChunckMasks.Length);
|
int chunckBufferLength = mask._incChunckMasks.Length + mask._excChunckMasks.Length;
|
||||||
|
_bufferHandler = MemoryAllocator.AllocAndInit<int>(bufferLength);
|
||||||
|
_chunckBufferHandler = MemoryAllocator.AllocAndInit<EcsMaskChunck>(chunckBufferLength);
|
||||||
|
var sortBuffer = UnsafeArray<int>.Manual(_bufferHandler.As<int>(), bufferLength);
|
||||||
|
var sortChunckBuffer = UnsafeArray<EcsMaskChunck>.Manual(_chunckBufferHandler.As<EcsMaskChunck>(), chunckBufferLength);
|
||||||
|
|
||||||
_sortIncBuffer = sortBuffer.Slice(0, mask._incs.Length);
|
_sortIncBuffer = sortBuffer.Slice(0, mask._incs.Length);
|
||||||
_sortIncBuffer.CopyFromArray_Unchecked(mask._incs);
|
_sortIncBuffer.CopyFromArray_Unchecked(mask._incs);
|
||||||
_sortExcBuffer = sortBuffer.Slice(mask._incs.Length, mask._excs.Length);
|
_sortExcBuffer = sortBuffer.Slice(mask._incs.Length, mask._excs.Length);
|
||||||
_sortExcBuffer.CopyFromArray_Unchecked(mask._excs);
|
_sortExcBuffer.CopyFromArray_Unchecked(mask._excs);
|
||||||
|
|
||||||
|
//EcsDebug.PrintError(_sortIncBuffer.ToArray());
|
||||||
|
//EcsDebug.PrintError(new Span<int>(_bufferHandler.GetPtrAs<int>(), _sortIncBuffer.Length).ToArray());
|
||||||
|
|
||||||
_sortIncChunckBuffer = sortChunckBuffer.Slice(0, mask._incChunckMasks.Length);
|
_sortIncChunckBuffer = sortChunckBuffer.Slice(0, mask._incChunckMasks.Length);
|
||||||
_sortIncChunckBuffer.CopyFromArray_Unchecked(mask._incChunckMasks);
|
_sortIncChunckBuffer.CopyFromArray_Unchecked(mask._incChunckMasks);
|
||||||
_sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length);
|
_sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length);
|
||||||
@ -565,8 +576,10 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
private void Cleanup(bool disposing)
|
private void Cleanup(bool disposing)
|
||||||
{
|
{
|
||||||
_sortIncBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcBuffer;
|
_bufferHandler.Dispose();
|
||||||
_sortIncChunckBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcChunckBuffer;
|
_chunckBufferHandler.Dispose();
|
||||||
|
//_sortIncBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcBuffer;
|
||||||
|
//_sortIncChunckBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcChunckBuffer;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -226,6 +226,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_isDestroyed = true;
|
||||||
_listeners.InvokeOnWorldDestroy();
|
_listeners.InvokeOnWorldDestroy();
|
||||||
_entityDispenser = null;
|
_entityDispenser = null;
|
||||||
_pools = null;
|
_pools = null;
|
||||||
@ -233,10 +234,9 @@ namespace DCFApixels.DragonECS
|
|||||||
_worlds[ID] = null;
|
_worlds[ID] = null;
|
||||||
ReleaseData(ID);
|
ReleaseData(ID);
|
||||||
_worldIdDispenser.Release(ID);
|
_worldIdDispenser.Release(ID);
|
||||||
_isDestroyed = true;
|
|
||||||
_poolTypeCode_2_CmpTypeIDs = null;
|
_poolTypeCode_2_CmpTypeIDs = null;
|
||||||
_cmpTypeCode_2_CmpTypeIDs = null;
|
_cmpTypeCode_2_CmpTypeIDs = null;
|
||||||
DisposeGroupPages();
|
DisposeGroups();
|
||||||
|
|
||||||
foreach (var item in _executorCoures)
|
foreach (var item in _executorCoures)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#if DISABLE_DEBUG
|
#if DISABLE_DEBUG
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
using DCFApixels.DragonECS.Core.Internal;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -275,50 +276,56 @@ namespace DCFApixels.DragonECS.Internal
|
|||||||
public static T* New<T>(int capacity) where T : unmanaged
|
public static T* New<T>(int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"{typeof(T).Name} - {Marshal.SizeOf<T>()} - {capacity} - {Marshal.SizeOf<T>() * capacity}");
|
//Console.WriteLine($"{typeof(T).Name} - {Marshal.SizeOf<T>()} - {capacity} - {Marshal.SizeOf<T>() * capacity}");
|
||||||
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
//return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||||
|
return MemoryAllocator.Alloc<T>(capacity).As<T>();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
//ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||||
|
ptr = MemoryAllocator.Alloc<T>(capacity).As<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
int newSize = MetaCache<T>.Size * capacity;
|
//int newSize = MetaCache<T>.Size * capacity;
|
||||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
//byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
//
|
||||||
for (int i = 0; i < newSize; i++)
|
//for (int i = 0; i < newSize; i++)
|
||||||
{
|
//{
|
||||||
*(newPointer + i) = 0;
|
// *(newPointer + i) = 0;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
return (T*)newPointer;
|
//return (T*)newPointer;
|
||||||
|
return MemoryAllocator.AllocAndInit<T>(capacity).As<T>();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
int newSize = MetaCache<T>.Size * capacity;
|
//int newSize = MetaCache<T>.Size * capacity;
|
||||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
//byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
//
|
||||||
for (int i = 0; i < newSize; i++)
|
//for (int i = 0; i < newSize; i++)
|
||||||
{
|
//{
|
||||||
*(newPointer + i) = 0;
|
// *(newPointer + i) = 0;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
ptr = (T*)newPointer;
|
//ptr = (T*)newPointer;
|
||||||
|
ptr = MemoryAllocator.AllocAndInit<T>(capacity).As<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Free(void* pointer)
|
public static void Free(void* pointer)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
//Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||||
|
MemoryAllocator.Free(dataPtr: pointer);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
//Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||||
|
MemoryAllocator.Free(dataPtr: pointer);
|
||||||
pointer = null;
|
pointer = null;
|
||||||
length = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
@ -337,19 +344,21 @@ namespace DCFApixels.DragonECS.Internal
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
||||||
{
|
{
|
||||||
return (T*)(Marshal.ReAllocHGlobal(
|
//return (T*)(Marshal.ReAllocHGlobal(
|
||||||
new IntPtr(oldPointer),
|
// new IntPtr(oldPointer),
|
||||||
new IntPtr(MetaCache<T>.Size * newCount))).ToPointer();
|
// new IntPtr(MetaCache<T>.Size * newCount))).ToPointer();
|
||||||
|
return MemoryAllocator.Realloc<T>(MemoryAllocator.Handler.FromDataPtr(oldPointer), newCount).As<T>();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
||||||
{
|
{
|
||||||
int sizeT = MetaCache<T>.Size;
|
//int sizeT = MetaCache<T>.Size;
|
||||||
T* result = (T*)Marshal.ReAllocHGlobal(
|
//T* result = (T*)Marshal.ReAllocHGlobal(
|
||||||
new IntPtr(oldPointer),
|
// new IntPtr(oldPointer),
|
||||||
new IntPtr(sizeT * newSize)).ToPointer();
|
// new IntPtr(sizeT * newSize)).ToPointer();
|
||||||
Init((byte*)result, sizeT * oldSize, sizeT * newSize);
|
//Init((byte*)result, sizeT * oldSize, sizeT * newSize);
|
||||||
return result;
|
//return result;
|
||||||
|
return MemoryAllocator.ReallocAndInit<T>(MemoryAllocator.Handler.FromDataPtr(oldPointer), oldSize, newSize).As<T>();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void Init(byte* pointer, int startByteIndex, int endByteIndex)
|
private static void Init(byte* pointer, int startByteIndex, int endByteIndex)
|
||||||
|
@ -16,6 +16,7 @@ namespace DCFApixels.DragonECS.Internal
|
|||||||
#endif
|
#endif
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
[DebuggerDisplay("Count: {Count}")]
|
||||||
internal class IdDispenser : IEnumerable<int>, IReadOnlyCollection<int>
|
internal class IdDispenser : IEnumerable<int>, IReadOnlyCollection<int>
|
||||||
{
|
{
|
||||||
private const int MIN_SIZE = 4;
|
private const int MIN_SIZE = 4;
|
||||||
|
333
src/Internal/MemoryAllocator.cs
Normal file
333
src/Internal/MemoryAllocator.cs
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Core.Internal
|
||||||
|
{
|
||||||
|
internal unsafe static class MemoryAllocator
|
||||||
|
{
|
||||||
|
private static IdDispenser _idDispenser;
|
||||||
|
private static HandlerDebugInfo[] _debugInfos;
|
||||||
|
//private static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||||
|
|
||||||
|
static MemoryAllocator()
|
||||||
|
{
|
||||||
|
StaticInit();
|
||||||
|
}
|
||||||
|
private static void StaticInit()
|
||||||
|
{
|
||||||
|
_idDispenser = new IdDispenser();
|
||||||
|
_debugInfos = new HandlerDebugInfo[32];
|
||||||
|
}
|
||||||
|
|
||||||
|
#region AllocAndInit
|
||||||
|
public static Handler AllocAndInit<T>(int count) where T : unmanaged
|
||||||
|
{
|
||||||
|
return AllocAndInit_Internal(Marshal.SizeOf<T>() * count, typeof(T));
|
||||||
|
}
|
||||||
|
public static Handler AllocAndInit(int byteLength)
|
||||||
|
{
|
||||||
|
return AllocAndInit_Internal(byteLength, null);
|
||||||
|
}
|
||||||
|
public static Handler AllocAndInit_Internal(int byteLength, Type type)
|
||||||
|
{
|
||||||
|
Handler result = Alloc_Internal(byteLength, type);
|
||||||
|
ClearAllocatedMemory(result.Ptr, 0, byteLength);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Alloc
|
||||||
|
public static Handler Alloc<T>(int count) where T : unmanaged
|
||||||
|
{
|
||||||
|
return Alloc_Internal(Marshal.SizeOf<T>() * count, typeof(T));
|
||||||
|
}
|
||||||
|
public static Handler Alloc(int byteLength)
|
||||||
|
{
|
||||||
|
return Alloc_Internal(byteLength, null);
|
||||||
|
}
|
||||||
|
public static Handler Alloc_Internal(int byteLength, Type type)
|
||||||
|
{
|
||||||
|
byteLength = byteLength == 0 ? 1 : byteLength;
|
||||||
|
int id = 0;
|
||||||
|
lock (_idDispenser)
|
||||||
|
{
|
||||||
|
if (_debugInfos.Length <= _idDispenser.Count)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _debugInfos, _debugInfos.Length << 1);
|
||||||
|
}
|
||||||
|
id = _idDispenser.UseFree();
|
||||||
|
}
|
||||||
|
Meta* newHandledPtr = (Meta*)Marshal.AllocHGlobal(byteLength + sizeof(Meta));
|
||||||
|
|
||||||
|
newHandledPtr->ID = id;
|
||||||
|
newHandledPtr->ByteLength = byteLength;
|
||||||
|
|
||||||
|
Handler handler = Handler.FromHandledPtr(newHandledPtr);
|
||||||
|
_debugInfos[id].stackTrace = new StackTrace();
|
||||||
|
_debugInfos[id].type = type;
|
||||||
|
_debugInfos[id].handler = handler;
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReallocAndInit
|
||||||
|
public static Handler ReallocAndInit<T>(void* target, int oldCount, int newCount) where T : unmanaged
|
||||||
|
{
|
||||||
|
return ReallocAndInit<T>(Handler.FromDataPtr(target), oldCount, newCount);
|
||||||
|
}
|
||||||
|
public static Handler ReallocAndInit(void* target, int oldByteLength, int newByteLength)
|
||||||
|
{
|
||||||
|
return ReallocAndInit(Handler.FromDataPtr(target), oldByteLength, newByteLength);
|
||||||
|
}
|
||||||
|
public static Handler ReallocAndInit<T>(Handler target, int oldCount, int newCount) where T : unmanaged
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf<T>();
|
||||||
|
return ReallocAndInit_Internal(target, size * oldCount, size * newCount, typeof(T));
|
||||||
|
}
|
||||||
|
public static Handler ReallocAndInit(Handler target, int oldByteLength, int newByteLength)
|
||||||
|
{
|
||||||
|
return ReallocAndInit_Internal(target, oldByteLength, newByteLength, null);
|
||||||
|
}
|
||||||
|
private static Handler ReallocAndInit_Internal(Handler target, int oldByteLength, int newByteLength, Type newType)
|
||||||
|
{
|
||||||
|
Handler result = Realloc_Internal(target, newByteLength, newType);
|
||||||
|
ClearAllocatedMemory(result.Ptr, oldByteLength, newByteLength - oldByteLength);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Realloc
|
||||||
|
public static Handler Realloc<T>(void* target, int newCount) where T : unmanaged
|
||||||
|
{
|
||||||
|
return Realloc<T>(Handler.FromDataPtr(target), Marshal.SizeOf<T>() * newCount);
|
||||||
|
}
|
||||||
|
public static Handler Realloc(void* target, int newByteLength)
|
||||||
|
{
|
||||||
|
return Realloc(Handler.FromDataPtr(target), newByteLength);
|
||||||
|
}
|
||||||
|
public static Handler Realloc<T>(Handler target, int newCount) where T : unmanaged
|
||||||
|
{
|
||||||
|
return Realloc_Internal(target, Marshal.SizeOf<T>() * newCount, typeof(T));
|
||||||
|
}
|
||||||
|
public static Handler Realloc(Handler target, int newByteLength)
|
||||||
|
{
|
||||||
|
return Realloc_Internal(target, newByteLength, null);
|
||||||
|
}
|
||||||
|
private static Handler Realloc_Internal(Handler target, int newByteLength, Type newType)
|
||||||
|
{
|
||||||
|
newByteLength = newByteLength == 0 ? 1 : newByteLength;
|
||||||
|
Meta* newHandledPtr = (Meta*)Marshal.ReAllocHGlobal((IntPtr)target.GetHandledPtr(), (IntPtr)newByteLength + sizeof(Meta));
|
||||||
|
Handler result = Handler.FromHandledPtr(newHandledPtr);
|
||||||
|
_debugInfos[newHandledPtr->ID].stackTrace = new StackTrace();
|
||||||
|
_debugInfos[newHandledPtr->ID].type = newType;
|
||||||
|
_debugInfos[newHandledPtr->ID].handler = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Free
|
||||||
|
public static void Free(ref Handler target)
|
||||||
|
{
|
||||||
|
Free_Internal(target.GetHandledPtr());
|
||||||
|
target = default;
|
||||||
|
}
|
||||||
|
public static void Free(void* dataPtr)
|
||||||
|
{
|
||||||
|
Free_Internal(((Meta*)dataPtr) - 1);
|
||||||
|
}
|
||||||
|
private static void Free_Internal(Meta* handledPtr)
|
||||||
|
{
|
||||||
|
lock (_idDispenser)
|
||||||
|
{
|
||||||
|
_idDispenser.Release(handledPtr->ID);
|
||||||
|
_debugInfos[handledPtr->ID] = default;
|
||||||
|
}
|
||||||
|
handledPtr->ID = default;
|
||||||
|
handledPtr->ByteLength = default;
|
||||||
|
Marshal.FreeHGlobal((IntPtr)handledPtr);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Other
|
||||||
|
internal static StateDebugInfo GetHandlerInfos_Debug()
|
||||||
|
{
|
||||||
|
StateDebugInfo result = default;
|
||||||
|
result.idDispenser = _idDispenser;
|
||||||
|
result.debugInfos = _debugInfos;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private static unsafe void ClearAllocatedMemory(IntPtr ptr, int startByte, int lengthInBytes)
|
||||||
|
{
|
||||||
|
Span<byte> memorySpan = new Span<byte>((byte*)ptr + startByte, lengthInBytes);
|
||||||
|
memorySpan.Clear();
|
||||||
|
}
|
||||||
|
internal struct Meta
|
||||||
|
{
|
||||||
|
public int ID;
|
||||||
|
public int ByteLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[DebuggerDisplay("{handler.DebuggerDisplay()}")]
|
||||||
|
#endif
|
||||||
|
internal struct HandlerDebugInfo
|
||||||
|
{
|
||||||
|
public StackTrace stackTrace;
|
||||||
|
public Type type;
|
||||||
|
public Handler handler;
|
||||||
|
}
|
||||||
|
internal struct StateDebugInfo
|
||||||
|
{
|
||||||
|
public HandlerDebugInfo[] debugInfos;
|
||||||
|
public IdDispenser idDispenser;
|
||||||
|
}
|
||||||
|
//private readonly struct AddLocker : IDisposable
|
||||||
|
//{
|
||||||
|
// private readonly ReaderWriterLockSlim _readerWriterLockSlim;
|
||||||
|
// public AddLocker(ReaderWriterLockSlim readerWriterLockSlim)
|
||||||
|
// {
|
||||||
|
// _readerWriterLockSlim = readerWriterLockSlim;
|
||||||
|
// readerWriterLockSlim.EnterWriteLock();
|
||||||
|
// }
|
||||||
|
// public void Dispose()
|
||||||
|
// {
|
||||||
|
// _readerWriterLockSlim.ExitWriteLock();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//private readonly struct RemoveLocker : IDisposable
|
||||||
|
//{
|
||||||
|
// private readonly ReaderWriterLockSlim _readerWriterLockSlim;
|
||||||
|
// public RemoveLocker(ReaderWriterLockSlim readerWriterLockSlim)
|
||||||
|
// {
|
||||||
|
// _readerWriterLockSlim = readerWriterLockSlim;
|
||||||
|
// readerWriterLockSlim.EnterReadLock();
|
||||||
|
// }
|
||||||
|
// public void Dispose()
|
||||||
|
// {
|
||||||
|
// _readerWriterLockSlim.ExitReadLock();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[DebuggerDisplay("{DebuggerDisplay()}")]
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
#endif
|
||||||
|
public readonly struct Handler
|
||||||
|
{
|
||||||
|
public static readonly Handler Empty = new Handler();
|
||||||
|
internal readonly Meta* Data; // Data[-1] is meta;
|
||||||
|
private Handler(Meta* dataPtr) { Data = dataPtr; }
|
||||||
|
public static Handler FromHandledPtr(void* ptr) { return new Handler(((Meta*)ptr) + 1); }
|
||||||
|
public static Handler FromDataPtr(void* ptr) { return new Handler((Meta*)ptr); }
|
||||||
|
internal Meta* GetHandledPtr() { return Data - 1; }
|
||||||
|
internal int GetID() { return GetHandledPtr()->ID; }
|
||||||
|
internal int GetByteLength() { return GetHandledPtr()->ByteLength; }
|
||||||
|
|
||||||
|
public bool IsEmpty { get { return Data == null; } }
|
||||||
|
public IntPtr Ptr { get { return (IntPtr)Data; } }
|
||||||
|
public T* As<T>() where T : unmanaged { return (T*)Ptr; }
|
||||||
|
|
||||||
|
#region Debugger
|
||||||
|
#if DEBUG
|
||||||
|
[RequiresDynamicCode("Calls System.Runtime.InteropServices.Marshal.SizeOf(Type)")]
|
||||||
|
internal unsafe string DebuggerDisplay()
|
||||||
|
{
|
||||||
|
if(Data == null)
|
||||||
|
{
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
Meta meta = GetHandledPtr()[0];
|
||||||
|
HandlerDebugInfo info = _debugInfos[meta.ID];
|
||||||
|
|
||||||
|
if (info.type == null)
|
||||||
|
{
|
||||||
|
return $"Count: {meta.ByteLength} Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"Count: {meta.ByteLength / Marshal.SizeOf(info.type)} {info.type.Name}";
|
||||||
|
}
|
||||||
|
[RequiresDynamicCode("Calls System.Runtime.InteropServices.Marshal.SizeOf(Type)")]
|
||||||
|
internal static Array CreateArray_Debug(Type type, int count, byte* data, int byteLength)
|
||||||
|
{
|
||||||
|
var array = Array.CreateInstance(type, count);
|
||||||
|
if (array.Length > 0)
|
||||||
|
{
|
||||||
|
Union union = default;
|
||||||
|
union.array = array;
|
||||||
|
fixed (byte* arrayPtr = union.bytes)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < byteLength; i++)
|
||||||
|
{
|
||||||
|
arrayPtr[i] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
private unsafe struct Union
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public Array array;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public byte[] bytes;
|
||||||
|
}
|
||||||
|
private class DebuggerProxy
|
||||||
|
{
|
||||||
|
private byte* _data;
|
||||||
|
private Type _type;
|
||||||
|
private int _count;
|
||||||
|
|
||||||
|
public bool IsAlive;
|
||||||
|
public Meta Meta;
|
||||||
|
public HandlerDebugInfo DebugInfo;
|
||||||
|
public Array Data;
|
||||||
|
|
||||||
|
public HandlerDebugInfo[] OtherHandlersInfo;
|
||||||
|
|
||||||
|
[RequiresDynamicCode("Calls System.Runtime.InteropServices.Marshal.SizeOf(Type)")]
|
||||||
|
public unsafe DebuggerProxy(Handler handler)
|
||||||
|
{
|
||||||
|
IsAlive = handler.Ptr.ToPointer() != null;
|
||||||
|
if (IsAlive == false) { return; }
|
||||||
|
|
||||||
|
Meta = handler.GetHandledPtr()[0];
|
||||||
|
_data = (byte*)handler.Ptr;
|
||||||
|
DebugInfo = _debugInfos[Meta.ID];
|
||||||
|
|
||||||
|
if (DebugInfo.type == null)
|
||||||
|
{
|
||||||
|
_type = typeof(byte);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_type = DebugInfo.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
var size = Marshal.SizeOf(_type);
|
||||||
|
_count = Meta.ByteLength / size;
|
||||||
|
|
||||||
|
Data = CreateArray_Debug(_type, _count, _data, Meta.ByteLength);
|
||||||
|
|
||||||
|
OtherHandlersInfo = _debugInfos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class MemoryAllocatorHandlerExtensions
|
||||||
|
{
|
||||||
|
public static void Dispose(this ref MemoryAllocator.Handler self)
|
||||||
|
{
|
||||||
|
MemoryAllocator.Free(ref self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user