diff --git a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs index 8c6f8f07..89c3cb92 100644 --- a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs +++ b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs @@ -29,7 +29,13 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA private const ulong PageSize = 0x1000; private const ulong HostAllocationGranularity = 0x10000; private const ulong GuestAllocationArenaAddress = 0x00006000_0000_0000; - private const ulong GuestAllocationArenaSize = 0x0100_0000; + // Full C++ runtimes can route large numbers of HLE-backed heap allocations + // through this arena. The original 16 MiB capacity could be exhausted + // during asset setup, turning a valid allocation request into a null + // pointer that failed later in unrelated guest code. Keep enough capacity + // for those workloads. Adapted from foufouadi's allocator-exhaustion + // investigation. + private const ulong GuestAllocationArenaSize = 0x2000_0000; private const ulong GuestAllocationArenaStartOffset = PageSize; private const ulong LargeDataReserveThreshold = 0x4000_0000UL; // 1 GiB private const ulong FullCommitRegionLimit = 4UL << 30; diff --git a/tests/SharpEmu.Libs.Tests/Memory/GuestMemoryAllocatorTests.cs b/tests/SharpEmu.Libs.Tests/Memory/GuestMemoryAllocatorTests.cs index e7e58c69..16e0d9a9 100644 --- a/tests/SharpEmu.Libs.Tests/Memory/GuestMemoryAllocatorTests.cs +++ b/tests/SharpEmu.Libs.Tests/Memory/GuestMemoryAllocatorTests.cs @@ -14,7 +14,7 @@ public sealed class GuestMemoryAllocatorTests public void FreedRangesAreReusedAndCoalesced() { using var memory = new PhysicalVirtualMemory(new FakeHostMemory()); - const ulong usableArenaSize = 0x0100_0000 - 0x1000; + const ulong usableArenaSize = 0x2000_0000 - 0x1000; Assert.True(memory.TryAllocateGuestMemory(0x4000, 0x1000, out var first)); Assert.True(memory.TryAllocateGuestMemory(0x8000, 0x1000, out var second)); @@ -34,6 +34,16 @@ public sealed class GuestMemoryAllocatorTests Assert.Equal(first, coalesced); } + [Fact] + public void ArenaSupportsAllocationsBeyondLegacySixteenMiBLimit() + { + using var memory = new PhysicalVirtualMemory(new FakeHostMemory()); + + Assert.True(memory.TryAllocateGuestMemory(0x0100_0000, 0x1000, out var first)); + Assert.True(memory.TryAllocateGuestMemory(0x0020_0000, 0x1000, out var beyondLegacyLimit)); + Assert.Equal(first + 0x0100_0000, beyondLegacyLimit); + } + [Fact] public void SegmentProtectionIsAppliedInContiguousRuns() {