Refactor AllocationManager and enhance debug tracking

Refactored `AllocationManager` to introduce intrusive allocation tracking with `AllocationHeader` structs for debug mode. Added lightweight allocation counters for non-debug mode. Enhanced memory leak detection with detailed stack traces and `MemoryLeakException`.

Simplified `AllocationInfo` by removing the `Allocator` property. Updated `AllocationOption` enum to remove `UnTracked` and clarified documentation.

Improved unsafe collections (`UnsafeArray`, `UnsafeStack`, etc.) with strongly-typed enumerators and better compatibility with `IEnumerable<T>`. Enhanced `UnsafeStack` with a dedicated `Enumerator` struct and consistent constructor parameters.

Refactored `MemoryLeakException` to support detailed allocation info and improved stack trace formatting. Simplified `MemoryUtility` by removing redundant null checks.

Added unit tests for `AllocationManager`, `UnsafeArray`, and `UnsafeStack` to validate memory management and functionality. Updated `Program.cs` with new examples.

Cleaned up namespaces, removed redundant `using` directives, and improved XML documentation. Applied `MethodImplOptions.AggressiveInlining` to performance-critical methods.
This commit is contained in:
2025-11-06 01:28:43 +09:00
parent b914716225
commit fbe72e33f7
17 changed files with 606 additions and 174 deletions

View File

@@ -0,0 +1,61 @@
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
namespace Misaki.HighPerformance.Test.UnitTest.Buffer;
[TestClass]
public class TestAllocationManager
{
[TestInitialize]
public void Initialize()
{
AllocationManager.EnableDebugLayer();
}
[TestMethod]
public void ShouldNotLeakTest()
{
try
{
var array = new UnsafeArray<int>(10, Allocator.Persistent);
var array2 = new UnsafeArray<int>(10, Allocator.Persistent);
array.Dispose();
array2.Dispose();
AllocationManager.Dispose();
}
finally
{
var leaks = AllocationManager.LiveHeapAllocationCount;
Assert.AreEqual(0, leaks);
}
}
[TestMethod]
public void ShouldLeakTest()
{
var array = new UnsafeArray<int>(10, Allocator.Persistent);
var array2 = new UnsafeArray<int>(10, Allocator.Persistent);
try
{
AllocationManager.Dispose();
}
catch (MemoryLeakException)
{
var leaks = AllocationManager.LiveHeapAllocationCount;
Assert.AreEqual(2, leaks);
return;
}
finally
{
array.Dispose();
array2.Dispose();
}
Assert.Fail("Expected MemoryLeakException was not thrown.");
}
}

View File

@@ -0,0 +1,56 @@
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
namespace Misaki.HighPerformance.Test.UnitTest.Collections;
[TestClass]
public class TestUnsafeArray
{
private UnsafeArray<int> _arr;
[TestInitialize]
public void Initialize()
{
_arr = new UnsafeArray<int>(16, Allocator.Persistent);
}
[TestCleanup]
public void Cleanup()
{
_arr.Dispose();
}
[TestMethod]
public void TestIndexAccess()
{
for (int i = 0; i < _arr.Count; i++)
{
_arr[i] = i * 10;
}
for (int i = 0; i < _arr.Count; i++)
{
Assert.AreEqual(i * 10, _arr[i]);
}
}
[TestMethod]
public void TestEnumeration()
{
_arr.Clear();
int expectedValue = 0;
foreach (var item in _arr)
{
Assert.AreEqual(expectedValue, item);
}
}
[TestMethod]
public void TestIsCreated()
{
Assert.IsTrue(_arr.IsCreated);
_arr.Dispose();
Assert.IsFalse(_arr.IsCreated);
}
}

View File

@@ -0,0 +1,68 @@
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Misaki.HighPerformance.Test.UnitTest.Collections;
[TestClass]
public class TestUnsafeStack
{
private UnsafeStack<int> _stack;
[TestInitialize]
public void Initialize()
{
_stack = new UnsafeStack<int>(16, Allocator.Persistent);
}
[TestCleanup]
public void Cleanup()
{
_stack.Dispose();
}
[TestMethod]
public void TestPushPop()
{
for (int i = 0; i < 10; i++)
{
_stack.Push(i);
}
Assert.AreEqual(10, _stack.Count);
for (int i = 9; i >= 0; i--)
{
int value = _stack.Pop();
Assert.AreEqual(i, value);
}
Assert.AreEqual(0, _stack.Count);
}
[TestMethod]
public void TestPeek()
{
_stack.Push(42);
int value = _stack.Peek();
Assert.AreEqual(42, value);
Assert.AreEqual(1, _stack.Count);
}
[TestMethod]
public void TestEnumeration()
{
for (int i = 0; i < 5; i++)
{
_stack.Push(i);
}
int expected = 4;
foreach (var item in _stack)
{
Assert.AreEqual(expected, item);
expected--;
}
}
}