feat(core): improve memory management and API safety
- JobScheduler now explicitly frees unmanaged memory in _jobInfoPool before disposal. - Removed the unused TempJobAllocator struct and implementation. - Refactored AllocationManager to use conditional compilation for safety checks, making MemoryHandle usage conditional. - Improved documentation in AllocationManager for clarity on allocation size and safety check behavior. - Added UnsafeSetCount method to UnsafeList<T> for direct count manipulation with validation. - Bumped AssemblyVersion in Jobs and LowLevel projects.
This commit is contained in:
@@ -786,8 +786,13 @@ public sealed unsafe partial class JobScheduler : IJobScheduler, IDisposable
|
||||
worker.Dispose();
|
||||
}
|
||||
|
||||
_jobInfoPool.Clear();
|
||||
_jobQueue.Clear();
|
||||
foreach (var info in _jobInfoPool)
|
||||
{
|
||||
if (info.pJobData != null)
|
||||
{
|
||||
NativeMemory.Free(info.pJobData);
|
||||
}
|
||||
}
|
||||
|
||||
_workSignal.Dispose();
|
||||
_cts.Dispose();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<AssemblyVersion>1.5.5</AssemblyVersion>
|
||||
<AssemblyVersion>1.5.6</AssemblyVersion>
|
||||
<Version>$(AssemblyVersion)</Version>
|
||||
<Authors>Misaki</Authors>
|
||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
namespace Misaki.HighPerformance.Jobs;
|
||||
|
||||
#if false
|
||||
public unsafe struct TempJobAllocator : IAllocator, IDisposable
|
||||
{
|
||||
private const int _FRAME_LATENCY = 4;
|
||||
private const int _MAGIC_ID = -559038737;
|
||||
|
||||
private VirtualArena* _pArena;
|
||||
private int _currentFrameCount;
|
||||
private int _currentFrameIndex;
|
||||
private fixed int _allocationsPerFrame[_FRAME_LATENCY];
|
||||
|
||||
private MemoryHandle _memoryHandle;
|
||||
private AllocationHandle _handle;
|
||||
|
||||
public readonly AllocationHandle Handle => _handle;
|
||||
|
||||
public void Initialize(nuint capacity)
|
||||
{
|
||||
var memoryHandle = default(MemoryHandle);
|
||||
|
||||
_pArena = (VirtualArena*)MemoryUtility.Malloc((nuint)(sizeof(VirtualArena) * _FRAME_LATENCY));
|
||||
_currentFrameCount = 0;
|
||||
_currentFrameIndex = 0;
|
||||
_memoryHandle = memoryHandle;
|
||||
|
||||
for (var i = 0; i < _FRAME_LATENCY; i++)
|
||||
{
|
||||
_pArena[i] = new VirtualArena(capacity);
|
||||
_allocationsPerFrame[i] = 0;
|
||||
}
|
||||
|
||||
_handle = new AllocationHandle
|
||||
{
|
||||
State = Unsafe.AsPointer(ref this),
|
||||
Alloc = &Allocate,
|
||||
Realloc = &Reallocate,
|
||||
Free = &Free,
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
IsValid = &IsValid,
|
||||
#else
|
||||
IsValid = null,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
private static void* Allocate(void* instance, nuint size, nuint alignment, AllocationOption allocationOption
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
, MemoryHandle* pHandle
|
||||
#endif
|
||||
)
|
||||
{
|
||||
var pSelf = (TempJobAllocator*)instance;
|
||||
var pCurrentArena = pSelf->_pArena + pSelf->_currentFrameIndex;
|
||||
var ptr = pCurrentArena->Allocate(size, alignment, allocationOption);
|
||||
if (ptr == null)
|
||||
{
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
*pHandle = MemoryHandle.Invalid;
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref pSelf->_allocationsPerFrame[pSelf->_currentFrameIndex]);
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
*pHandle = new MemoryHandle(_MAGIC_ID, pSelf->_currentFrameCount);
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
private static void* Reallocate(void* instance, void* ptr, nuint oldSize, nuint newSize, nuint alignment, AllocationOption allocationOption
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
, MemoryHandle* pHandle
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (ptr == null)
|
||||
{
|
||||
return Allocate(instance, newSize, alignment, allocationOption
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
, pHandle
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
var pSelf = (TempJobAllocator*)instance;
|
||||
var pCurrentArena = pSelf->_pArena + pSelf->_currentFrameIndex;
|
||||
var newPtr = pCurrentArena->Allocate(newSize, alignment, allocationOption);
|
||||
if (newPtr == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MemoryUtility.MemCpy(ptr, newPtr, Math.Min(oldSize, newSize));
|
||||
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
private static void Free(void* instance, void* ptr
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
, MemoryHandle handle
|
||||
#endif
|
||||
)
|
||||
{
|
||||
var pSelf = (TempJobAllocator*)instance;
|
||||
Interlocked.Decrement(ref pSelf->_allocationsPerFrame[pSelf->_currentFrameIndex]);
|
||||
}
|
||||
|
||||
#if ENABLE_SAFETY_CHECKS
|
||||
private static bool IsValid(void* instance, MemoryHandle handle)
|
||||
{
|
||||
var pSelf = (TempJobAllocator*)instance;
|
||||
return handle.ID == _MAGIC_ID && handle.Generation > pSelf->_currentFrameCount - _FRAME_LATENCY;
|
||||
}
|
||||
#endif
|
||||
|
||||
public int AdvanceFrame()
|
||||
{
|
||||
var allocations = Interlocked.Exchange(ref _allocationsPerFrame[_currentFrameIndex], 0);
|
||||
|
||||
_currentFrameCount++;
|
||||
_currentFrameIndex = _currentFrameCount % _FRAME_LATENCY;
|
||||
|
||||
(_pArena + _currentFrameIndex)->Reset();
|
||||
|
||||
return allocations;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
for (var i = 0; i < _FRAME_LATENCY; i++)
|
||||
{
|
||||
_pArena[i].Dispose();
|
||||
}
|
||||
|
||||
AllocationManager.HeapFree(_pArena, _memoryHandle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user