diff --git a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs index 0781356d..28abd50a 100644 --- a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs +++ b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs @@ -238,7 +238,15 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA var alignedSize = (size + 0xFFF) & ~0xFFFUL; var protection = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; var hostProtection = executable ? HostPageProtection.ReadWriteExecute : HostPageProtection.ReadWrite; - var result = _hostMemory.Allocate(desiredAddress, alignedSize, hostProtection); + + // Reserve address space only for very large non-executable regions; commit is done lazily later. + var reservedOnly = !executable && + alignedSize >= LargeDataReserveThreshold && + alignedSize > FullCommitRegionLimit; + + var result = reservedOnly + ? _hostMemory.Reserve(desiredAddress, alignedSize, HostPageProtection.ReadWrite) + : _hostMemory.Allocate(desiredAddress, alignedSize, hostProtection); if (result == 0) { return false; @@ -252,6 +260,8 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA return false; } + var state = reservedOnly ? ReserveRegion(actualAddress, alignedSize) : "n/a"; + _gate.EnterWriteLock(); try { @@ -260,7 +270,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA VirtualAddress = actualAddress, Size = alignedSize, IsExecutable = executable, - IsReservedOnly = false, + IsReservedOnly = reservedOnly, Protection = protection }); } @@ -269,6 +279,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA _gate.ExitWriteLock(); } + var allocationKind = executable ? "executable memory" : "data memory"; TraceVmem($"Allocated exact {allocationKind}: 0x{actualAddress:X16} - 0x{actualAddress + alignedSize:X16} ({alignedSize} bytes)"); return true; @@ -361,44 +372,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA var actualAddress = result; - var lazyPrimeState = "n/a"; - if (reservedOnly) - { - var primeBytes = Math.Min(alignedSize, LazyReservePrimeBytes); - if (primeBytes != 0) - { - ulong committedBytes = 0; - while (committedBytes < primeBytes) - { - var remaining = primeBytes - committedBytes; - var chunkBytes = Math.Min(remaining, LazyReservePrimeChunkBytes); - var commitAddress = actualAddress + committedBytes; - if (!_hostMemory.Commit(commitAddress, chunkBytes, HostPageProtection.ReadWrite)) - { - break; - } - - committedBytes += chunkBytes; - } - - if (committedBytes != 0) - { - lazyPrimeState = committedBytes == primeBytes - ? $"ok:{committedBytes:X}" - : $"partial:{committedBytes:X}/{primeBytes:X}"; - TraceVmem($"Primed lazy region: 0x{actualAddress:X16} - 0x{actualAddress + committedBytes:X16} ({committedBytes} bytes)"); - } - else - { - lazyPrimeState = $"fail:{primeBytes:X}"; - TraceVmem($"Failed to prime lazy region at 0x{actualAddress:X16} ({primeBytes} bytes), continuing with on-demand commit"); - } - } - else - { - lazyPrimeState = "skip:0"; - } - } + var lazyPrimeState = reservedOnly ? ReserveRegion(actualAddress, alignedSize) : "n/a"; _gate.EnterWriteLock(); try @@ -425,6 +399,41 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA return actualAddress; } + private string ReserveRegion(ulong actualAddress, ulong alignedSize) + { + var primeBytes = Math.Min(alignedSize, LazyReservePrimeBytes); + if (primeBytes == 0) + { + return "skip:0"; + } + + ulong committedBytes = 0; + while (committedBytes < primeBytes) + { + var remaining = primeBytes - committedBytes; + var chunkBytes = Math.Min(remaining, LazyReservePrimeChunkBytes); + var commitAddress = actualAddress + committedBytes; + if (!_hostMemory.Commit(commitAddress, chunkBytes, HostPageProtection.ReadWrite)) + { + break; + } + + committedBytes += chunkBytes; + } + + if (committedBytes != 0) + { + var state = committedBytes == primeBytes + ? $"ok:{committedBytes:X}" + : $"partial:{committedBytes:X}/{primeBytes:X}"; + TraceVmem($"region: 0x{actualAddress:X16} - 0x{actualAddress + committedBytes:X16} ({committedBytes} bytes)"); + return state; + } + + TraceVmem($"Failed to reserve region at 0x{actualAddress:X16} ({primeBytes} bytes)!"); + return $"fail:{primeBytes:X}"; + } + public bool TryBackFixedRange(ulong address, ulong size, bool executable) { if (size == 0)