From 533df844d894a8858aafb7b4d619683fcaddabc0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sat, 5 Mar 2011 18:28:59 +1300 Subject: [PATCH] pool CellInfo[,] to save massive amounts of memory (now uses only 512K for CellInfos on default-sized maps) --- OpenRA.Mods.RA/Move/PathFinder.cs | 69 ++++++++++++++++--------------- OpenRA.Mods.RA/Move/PathSearch.cs | 58 +++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 39 deletions(-) diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index 4a64f55fe8..9be2e19f5d 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -87,12 +87,13 @@ namespace OpenRA.Mods.RA.Move { using (new PerfSample("Pathfinder")) { - while (!search.queue.Empty) - { - var p = search.Expand( world ); - if (search.heuristic(p) == 0) - return MakePath(search.cellInfo, p); - } + using(search) + while (!search.queue.Empty) + { + var p = search.Expand(world); + if (search.heuristic(p) == 0) + return MakePath(search.cellInfo, p); + } // no path exists return new List(); @@ -113,33 +114,35 @@ namespace OpenRA.Mods.RA.Move ret.Add(pathNode); CheckSanePath(ret); return ret; - } - - - - public List FindBidiPath( /* searches from both ends toward each other */ - PathSearch fromSrc, - PathSearch fromDest) - { - using (new PerfSample("Pathfinder")) - { - while (!fromSrc.queue.Empty && !fromDest.queue.Empty) - { - /* make some progress on the first search */ - var p = fromSrc.Expand( world ); - - if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, p); - - /* make some progress on the second search */ - var q = fromDest.Expand( world ); - - if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, q); - } - - return new List(); - } + } + + + + public List FindBidiPath( /* searches from both ends toward each other */ + PathSearch fromSrc, + PathSearch fromDest) + { + using (new PerfSample("Pathfinder")) + { + using (fromSrc) + using (fromDest) + while (!fromSrc.queue.Empty && !fromDest.queue.Empty) + { + /* make some progress on the first search */ + var p = fromSrc.Expand(world); + + if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) + return MakeBidiPath(fromSrc, fromDest, p); + + /* make some progress on the second search */ + var q = fromDest.Expand(world); + + if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) + return MakeBidiPath(fromSrc, fromDest, q); + } + + return new List(); + } } static List MakeBidiPath(PathSearch a, PathSearch b, int2 p) diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index e1fb26d679..054fa504e8 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -15,7 +15,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Move { - public class PathSearch + public class PathSearch : IDisposable { World world; public CellInfo[ , ] cellInfo; @@ -191,15 +191,47 @@ namespace OpenRA.Mods.RA.Move search.AddInitialCell( sl ); return search; + } + + static readonly Queue cellInfoPool = new Queue(); + + static CellInfo[,] GetFromPool() + { + lock (cellInfoPool) + return cellInfoPool.Dequeue(); + } + + static void PutBackIntoPool(CellInfo[,] ci) + { + lock (cellInfoPool) + cellInfoPool.Enqueue(ci); } CellInfo[ , ] InitCellInfo() - { - var cellInfo = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ]; + { + CellInfo[,] result = null; + while (cellInfoPool.Count > 0) + { + var cellInfo = GetFromPool(); + if (cellInfo.GetUpperBound(0) != world.Map.MapSize.X - 1 || + cellInfo.GetUpperBound(1) != world.Map.MapSize.Y - 1) + { + Game.Debug("Discarding old pooled CellInfo of wrong size."); + continue; + } + + result = cellInfo; + break; + } + + if (result == null) + result = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ]; + for( int x = 0 ; x < world.Map.MapSize.X ; x++ ) for( int y = 0 ; y < world.Map.MapSize.Y ; y++ ) - cellInfo[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false ); - return cellInfo; + result[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false ); + + return result; } public static Func DefaultEstimator( int2 destination ) @@ -211,6 +243,20 @@ namespace OpenRA.Mods.RA.Move int straight = Math.Abs( d.X - d.Y ); return (3400 * diag / 24) + (100 * straight); }; - } + } + + bool disposed; + public void Dispose() + { + if (disposed) + return; + + disposed = true; + GC.SuppressFinalize(this); + PutBackIntoPool(cellInfo); + cellInfo = null; + } + + ~PathSearch() { Dispose(); } } }