using System; using System.Collections.Generic; namespace VMdemo.Simulation { public readonly struct EvictionInfo { public EvictionInfo(bool hasEvicted, ulong evictedVpn, ulong evictedPfn) { HasEvicted = hasEvicted; EvictedVpn = evictedVpn; EvictedPfn = evictedPfn; } public bool HasEvicted { get; } public ulong EvictedVpn { get; } public ulong EvictedPfn { get; } public static EvictionInfo None => new EvictionInfo(false, 0UL, 0UL); } public readonly struct AllocationResult { public AllocationResult(ulong assignedPfn, bool wasAlreadyResident, EvictionInfo eviction) { AssignedPfn = assignedPfn; WasAlreadyResident = wasAlreadyResident; Eviction = eviction; } public ulong AssignedPfn { get; } public bool WasAlreadyResident { get; } public EvictionInfo Eviction { get; } } public class PhysicalMemoryManager { private readonly Queue _fifoQueue = new Queue(); private readonly Dictionary _residentByVpn = new Dictionary(); private ulong _nextFreeFrame; public PhysicalMemoryManager(ulong frameCount) { if (frameCount < 1UL) { throw new ArgumentOutOfRangeException(nameof(frameCount), "frameCount 必须 >= 1。"); } FrameCount = frameCount; _nextFreeFrame = 0UL; } public ulong FrameCount { get; } public int ResidentCount => _residentByVpn.Count; public bool TryGetResidentPfn(ulong vpn, out ulong pfn) { return _residentByVpn.TryGetValue(vpn, out pfn); } public AllocationResult AllocateForVpn(ulong vpn) { if (_residentByVpn.TryGetValue(vpn, out var existingPfn)) { return new AllocationResult(existingPfn, true, EvictionInfo.None); } EvictionInfo evictionInfo; ulong assignedPfn; if (_nextFreeFrame < FrameCount) { assignedPfn = _nextFreeFrame; _nextFreeFrame++; evictionInfo = EvictionInfo.None; } else { if (_fifoQueue.Count == 0) { throw new InvalidOperationException("内存已满但 FIFO 队列为空,状态异常。"); } var victim = _fifoQueue.Dequeue(); if (!_residentByVpn.Remove(victim.Vpn)) { throw new InvalidOperationException("FIFO 淘汰项未出现在驻留映射中,状态异常。"); } assignedPfn = victim.Pfn; evictionInfo = new EvictionInfo(true, victim.Vpn, victim.Pfn); } _residentByVpn[vpn] = assignedPfn; _fifoQueue.Enqueue(new ResidentPage(vpn, assignedPfn)); return new AllocationResult(assignedPfn, false, evictionInfo); } public IReadOnlyList GetFifoVpnOrder() { var order = new List(_fifoQueue.Count); foreach (var page in _fifoQueue) { order.Add(page.Vpn); } return order; } public string FormatFifoQueue() { var order = GetFifoVpnOrder(); if (order.Count == 0) { return "FIFO=[]"; } return $"FIFO=[{string.Join(",", order)}]"; } private readonly struct ResidentPage { public ResidentPage(ulong vpn, ulong pfn) { Vpn = vpn; Pfn = pfn; } public ulong Vpn { get; } public ulong Pfn { get; } } } }