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:
2026-03-31 19:58:47 +09:00
parent 669185ab0c
commit abb0cd88ea
6 changed files with 63 additions and 161 deletions

View File

@@ -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();

View File

@@ -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>

View File

@@ -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