diff --git a/Ryujinx.HLE/Memory/ArenaAllocator.cs b/Ryujinx.HLE/Memory/ArenaAllocator.cs index 5e15f46a5..9bcb7873e 100644 --- a/Ryujinx.HLE/Memory/ArenaAllocator.cs +++ b/Ryujinx.HLE/Memory/ArenaAllocator.cs @@ -45,6 +45,33 @@ namespace Ryujinx.HLE.Memory Rg.Position += Size; Rg.Size -= Size; + if (Rg.Size == 0) + { + //Region is empty, just remove it. + FreeRegions.Remove(Node); + } + else if (Node.Previous != null) + { + //Re-sort based on size (smaller first). + Node = Node.Previous; + + FreeRegions.Remove(Node.Next); + + while (Node != null && (ulong)Node.Value.Size > (ulong)Rg.Size) + { + Node = Node.Previous; + } + + if (Node != null) + { + FreeRegions.AddAfter(Node, Rg); + } + else + { + FreeRegions.AddFirst(Rg); + } + } + TotalUsedSize += Size; return true; @@ -65,7 +92,7 @@ namespace Ryujinx.HLE.Memory Region NewRg = new Region(Position, Size); LinkedListNode Node = FreeRegions.First; - LinkedListNode PrevSz = Node; + LinkedListNode PrevSz = null; while (Node != null) { @@ -77,27 +104,38 @@ namespace Ryujinx.HLE.Memory if (Rg.Position == End) { + //Current region position matches the end of the freed region, + //just merge the two and remove the current region from the list. NewRg.Size += Rg.Size; FreeRegions.Remove(Node); } else if (RgEnd == Position) { + //End of the current region matches the position of the freed region, + //just merge the two and remove the current region from the list. NewRg.Position = Rg.Position; NewRg.Size += Rg.Size; FreeRegions.Remove(Node); } - else if ((ulong)Rg.Size < (ulong)NewRg.Size && - (ulong)Rg.Size > (ulong)PrevSz.Value.Size) + else { - PrevSz = Node; + if (PrevSz == null) + { + PrevSz = Node; + } + else if ((ulong)Rg.Size < (ulong)NewRg.Size && + (ulong)Rg.Size > (ulong)PrevSz.Value.Size) + { + PrevSz = Node; + } } Node = NextNode; } - if ((ulong)PrevSz.Value.Size < (ulong)Size) + if (PrevSz != null && (ulong)PrevSz.Value.Size < (ulong)Size) { FreeRegions.AddAfter(PrevSz, NewRg); }