Improved GameFileCache memory usage

This commit is contained in:
dexy 2019-12-11 00:31:56 +11:00
parent d5c0bc2477
commit 0aa220e0c2
8 changed files with 67 additions and 7 deletions

View File

@ -226,6 +226,10 @@ namespace CodeWalker.GameFiles
//{ } //{ }
#endregion #endregion
#if !DEBUG
Meta = null;
#endif
} }

View File

@ -2257,6 +2257,13 @@ namespace CodeWalker.GameFiles
} }
public void BeginFrame()
{
lock (requestSyncRoot)
{
mainCache.BeginFrame();
}
}
public bool ContentThreadProc() public bool ContentThreadProc()

View File

@ -11,7 +11,8 @@ namespace CodeWalker
{ {
public long MaxMemoryUsage = 536870912; //512mb public long MaxMemoryUsage = 536870912; //512mb
public long CurrentMemoryUsage = 0; public long CurrentMemoryUsage = 0;
public double CacheTime = 5.0; //seconds to keep something that's not used public double CacheTime = 10.0; //seconds to keep something that's not used
public DateTime CurrentTime = DateTime.Now;
private LinkedList<TVal> loadedList = new LinkedList<TVal>(); private LinkedList<TVal> loadedList = new LinkedList<TVal>();
private Dictionary<TKey, LinkedListNode<TVal>> loadedListDict = new Dictionary<TKey, LinkedListNode<TVal>>(); private Dictionary<TKey, LinkedListNode<TVal>> loadedListDict = new Dictionary<TKey, LinkedListNode<TVal>>();
@ -33,6 +34,12 @@ namespace CodeWalker
CacheTime = cacheTime; CacheTime = cacheTime;
} }
public void BeginFrame()
{
CurrentTime = DateTime.Now;
Compact();
}
public TVal TryGet(TKey key) public TVal TryGet(TKey key)
{ {
LinkedListNode<TVal> lln = null; LinkedListNode<TVal> lln = null;
@ -40,7 +47,7 @@ namespace CodeWalker
{ {
loadedList.Remove(lln); loadedList.Remove(lln);
loadedList.AddLast(lln); loadedList.AddLast(lln);
lln.Value.LastUseTime = DateTime.Now; lln.Value.LastUseTime = CurrentTime;
} }
return (lln != null) ? lln.Value : null; return (lln != null) ? lln.Value : null;
} }
@ -65,7 +72,7 @@ namespace CodeWalker
int iter = 0, maxiter = 2; int iter = 0, maxiter = 2;
while (!CanAdd() && (iter<maxiter)) while (!CanAdd() && (iter<maxiter))
{ {
while ((!CanAdd()) && (oldlln != null) && ((DateTime.Now - oldlln.Value.LastUseTime).TotalSeconds > cachetime)) while ((!CanAdd()) && (oldlln != null) && ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds > cachetime))
{ {
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage); Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
loadedListDict.Remove(oldlln.Value.Key); loadedListDict.Remove(oldlln.Value.Key);
@ -113,16 +120,33 @@ namespace CodeWalker
{ {
loadedListDict.Remove(key); loadedListDict.Remove(key);
loadedList.Remove(n); loadedList.Remove(n);
CurrentMemoryUsage -= n.Value.MemoryUsage; Interlocked.Add(ref CurrentMemoryUsage, -n.Value.MemoryUsage);
} }
} }
public void Compact()
{
var oldlln = loadedList.First;
while (oldlln != null)
{
if ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds < CacheTime) break;
var nextln = oldlln.Next;
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
loadedListDict.Remove(oldlln.Value.Key);
loadedList.Remove(oldlln); //gc should free up memory later..
oldlln.Value = null;
oldlln = nextln;
}
}
} }
public abstract class Cacheable<TKey> public abstract class Cacheable<TKey>
{ {
public TKey Key; public TKey Key;
public DateTime LastUseTime = DateTime.Now; public DateTime LastUseTime;
public long MemoryUsage; public long MemoryUsage;
} }

View File

@ -165,6 +165,8 @@ namespace CodeWalker
{ {
if (FileCache.IsInited) if (FileCache.IsInited)
{ {
FileCache.BeginFrame();
bool fcItemsPending = FileCache.ContentThreadProc(); bool fcItemsPending = FileCache.ContentThreadProc();
if (!fcItemsPending) if (!fcItemsPending)

View File

@ -213,13 +213,14 @@ namespace CodeWalker.Peds
if (pauserendering) return; if (pauserendering) return;
GameFileCache.BeginFrame();
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
{ return; } //couldn't get a lock, try again next time { return; } //couldn't get a lock, try again next time
UpdateControlInputs(elapsed); UpdateControlInputs(elapsed);
//space.Update(elapsed); //space.Update(elapsed);
Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y); Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y);

View File

@ -1652,6 +1652,23 @@ namespace CodeWalker.Rendering
for (int i = 0; i < ents.Count; i++) //make sure to remove the renderable references to avoid hogging memory
{
var ent = ents[i];
ent.LodManagerRenderable = null;
}
foreach (var ent in RequiredParents.Keys)
{
var pcnode = ent.LodManagerChildren?.First;
while (pcnode != null)//maybe can improve performance of this
{
var pcent = pcnode.Value;
pcent.LodManagerRenderable = null;
pcnode = pcnode.Next;
}
}
RenderWorldYmapExtras(); RenderWorldYmapExtras();
} }
@ -3586,6 +3603,8 @@ namespace CodeWalker.Rendering
var ent = ymap.AllEntities[i]; var ent = ymap.AllEntities[i];
RootEntities.Remove(ent); RootEntities.Remove(ent);
ent.LodManagerChildren?.Clear(); ent.LodManagerChildren?.Clear();
ent.LodManagerChildren = null;
ent.LodManagerRenderable = null;
if ((ent.Parent != null) && (ent.Parent.Ymap != ymap)) if ((ent.Parent != null) && (ent.Parent.Ymap != ymap))
{ {
ent.Parent.LodManagerRemoveChild(ent); ent.Parent.LodManagerRemoveChild(ent);

View File

@ -164,13 +164,14 @@ namespace CodeWalker.Vehicles
if (pauserendering) return; if (pauserendering) return;
GameFileCache.BeginFrame();
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
{ return; } //couldn't get a lock, try again next time { return; } //couldn't get a lock, try again next time
UpdateControlInputs(elapsed); UpdateControlInputs(elapsed);
//space.Update(elapsed); //space.Update(elapsed);
Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y); Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y);

View File

@ -398,6 +398,8 @@ namespace CodeWalker
if (pauserendering) return; if (pauserendering) return;
GameFileCache.BeginFrame();
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
{ return; } //couldn't get a lock, try again next time { return; } //couldn't get a lock, try again next time