Skip to content

Commit fbce191

Browse files
committed
lazy-load cached files to reduce memory footprint (WS Shareable)
update and use LastAccessTime of cached files to make LRU more reasonable
1 parent d896870 commit fbce191

File tree

1 file changed

+61
-24
lines changed

1 file changed

+61
-24
lines changed

DependenciesLib/BinaryCache.cs

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
using System.Diagnostics;
55
using Dependencies.ClrPh;
66
using System.ComponentModel;
7-
7+
using System.Linq;
8+
89
namespace Dependencies
910
{
1011

@@ -292,8 +293,7 @@ public class BinaryCacheImpl : BinaryCache
292293
{
293294
public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)
294295
{
295-
296-
BinaryDatabase = new Dictionary<string, PE>();
296+
BinaryDatabase = new Dictionary<string, Lazy<PE>>();
297297
BinaryDatabaseLock = new Object();
298298
LruCache = new List<string>();
299299

@@ -306,10 +306,13 @@ public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)
306306

307307
public override void Load()
308308
{
309-
// "warm up" the cache
310-
foreach (var CachedBinary in Directory.EnumerateFiles(BinaryCacheFolderPath))
311-
{
312-
GetBinaryAsync(CachedBinary);
309+
// load cached file order by LastAccessTime to make LRU always available
310+
foreach (var cachedBinaryFile in new DirectoryInfo(BinaryCacheFolderPath).EnumerateFiles()
311+
.OrderByDescending(fi => fi.LastAccessTime))
312+
{
313+
var peHash = cachedBinaryFile.Name;
314+
LruCache.Add(peHash);
315+
BinaryDatabase.Add(peHash, new Lazy<PE>(() => LoadCachedBinary(peHash), true));
313316
}
314317

315318
string System32Folder = Environment.GetFolderPath(Environment.SpecialFolder.System);
@@ -339,9 +342,7 @@ public override void Load()
339342
{
340343
GetBinaryAsync(Path.Combine(SysWow64Folder, KnownDll));
341344
}
342-
343345
}
344-
345346
}
346347

347348
public override void Unload()
@@ -358,7 +359,11 @@ public override void Unload()
358359
// Force map unloading before deleting file
359360
if (BinaryDatabase.ContainsKey(PeHash))
360361
{
361-
BinaryDatabase[PeHash].Unload();
362+
var lazyPE = BinaryDatabase[PeHash];
363+
if (lazyPE.IsValueCreated)
364+
{
365+
lazyPE.Value.Unload();
366+
}
362367
}
363368

364369
try
@@ -371,20 +376,53 @@ public override void Unload()
371376
// so only the last one alive can clear the cache.
372377
Debug.WriteLine("[BinaryCache] Could not unload file {0:s} : {1:s} ", CachedBinary, uae);
373378
}
374-
375379
}
376380
}
377381

378-
379382
// flush the cache
380383
BinaryDatabase.Clear();
381384
}
382385

386+
private PE LoadCachedBinary(string peHash)
387+
{
388+
var cachedBinaryFile = Path.Combine(BinaryCacheFolderPath, peHash);
389+
if (!NativeFile.Exists(cachedBinaryFile))
390+
{
391+
lock (BinaryDatabaseLock)
392+
{
393+
LruCache.Remove(peHash);
394+
BinaryDatabase.Remove(peHash);
395+
}
396+
return null;
397+
}
398+
399+
PE cachedPE = new PE(cachedBinaryFile);
400+
try
401+
{
402+
// update LastAccessTime to save LRU to disk
403+
// note: Windows from Vista disable updating LastAccessTime by default,
404+
// so we have to update it manually.
405+
new FileInfo(cachedBinaryFile).LastAccessTime = DateTime.Now;
406+
}
407+
catch { }
408+
409+
if (!cachedPE.Load())
410+
{
411+
lock (BinaryDatabaseLock)
412+
{
413+
LruCache.Remove(peHash);
414+
BinaryDatabase.Remove(peHash);
415+
}
416+
return null;
417+
}
418+
419+
return cachedPE;
420+
}
421+
383422
public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callback = null)
384423
{
385424
BackgroundWorker bw = new BackgroundWorker();
386425
bw.DoWork += (sender, e) => {
387-
388426
GetBinary(PePath);
389427
};
390428

@@ -393,7 +431,6 @@ public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callbac
393431
bw.RunWorkerCompleted += Callback;
394432
}
395433

396-
397434
bw.RunWorkerAsync();
398435
}
399436

@@ -419,25 +456,25 @@ public override PE GetBinary(string PePath)
419456
// Cache "miss"
420457
if (!hit)
421458
{
422-
423459
string DestFilePath = Path.Combine(BinaryCacheFolderPath, PeHash);
424460
if (!File.Exists(DestFilePath) && (DestFilePath != PePath))
425461
{
426462
// Debug.WriteLine(String.Format("FileCopy from {0:s} to {1:s}", PePath, DestFilePath), "BinaryCache");
427463
NativeFile.Copy(PePath, DestFilePath);
428-
}
429-
430-
PE NewShadowBinary = new PE(DestFilePath);
431-
NewShadowBinary.Load();
432-
433-
LruCache.Add(PeHash);
434-
BinaryDatabase.Add(PeHash, NewShadowBinary);
464+
}
465+
466+
LruCache.Add(PeHash);
467+
BinaryDatabase.Add(PeHash, new Lazy<PE>(() => LoadCachedBinary(PeHash)));
435468
}
436469
}
437470

438471
// Cache "Hit"
439472
UpdateLru(PeHash);
440-
PE ShadowBinary = BinaryDatabase[PeHash];
473+
PE ShadowBinary = BinaryDatabase[PeHash].Value;
474+
if (ShadowBinary == null)
475+
{
476+
return null;
477+
}
441478
ShadowBinary.Filepath = Path.GetFullPath(PePath); // convert any paths to an absolute one.
442479

443480
Debug.WriteLine(String.Format("File {0:s} loaded from {1:s}", PePath, Path.Combine(BinaryCacheFolderPath, PeHash)), "BinaryCache");
@@ -465,7 +502,7 @@ protected void UpdateLru(string PeHash)
465502

466503
#region Members
467504
private List<string> LruCache;
468-
private Dictionary<string, PE> BinaryDatabase;
505+
private Dictionary<string, Lazy<PE>> BinaryDatabase;
469506
private Object BinaryDatabaseLock;
470507

471508
private string BinaryCacheFolderPath;

0 commit comments

Comments
 (0)