如何摆脱 LOH 碎片并优化代码

How to get rid of LOH Fragmentations and Optimize the code

我有一个简单的线程 运行 从目录中清除一些缓存文件。大多数文件是超过 80KBytes 的大对象。目录中大约有 2000 个这样的文件。如下图。

while (true)
{
  if (Directory.Exists(CACHE_PATH))
  {
    List<FileInfo> filesList = new DirectoryInfo(CACHE_PATH).GetFiles("*", SearchOption.AllDirectories).ToList();
    long directorySize = filesList.Sum(e => e.Length);

    if (directorySize > CACHE_MAX_SIZE)
    {
      filesList.Sort(new FileInfoAccessTimeComparer());
      while (directorySize > CACHE_MAX_SIZE * 0.75)
      {
        directorySize -= filesList[0].Length;
        filesList[0].Delete();
        filesList.RemoveAt(0);
      }
    }
    filesList.Clear();
    filesList = null;
  }
  Thread.Sleep(CACHE_CLEANUP_INTERVAL);
}

我想知道这种方法是否会导致任何 LOH 碎片,我应该使用除 List 之外的任何其他类型的可枚举类型(例如 ArrayPool)。

此外,这是一个很好的使用方法吗

List<FileInfo> filesList = new DirectoryInfo(CACHE_PATH).GetFiles("*", SearchOption.AllDirectories).ToList();

而不是

FileInfo[] fileInfos = new DirectoryInfo(CACHE_PATH).GetFiles("*", SearchOption.AllDirectories);
List<FileInfo> filesList = fileInfos.ToList();

不存在大对象堆问题,因为您的底层数组很小(只有几千个条目)并且您的 FileInfo 对象很小。 FileInfo 只是元数据 - 它不是文件的 内容

您的代码没有明显的问题。您可以避免使用 RemoveAt 来保存许多(在幕后)不必要的数组分配/调整大小操作。下面的代码将实现这一点(并且还避免了对 ToList 调用的需要):

while (true)
{
    if (Directory.Exists(CACHE_PATH))
    {
        var filesList = new DirectoryInfo(CACHE_PATH).GetFiles("*", SearchOption.AllDirectories);
        long directorySize = filesList.Sum(e => e.Length);

        if (directorySize > CACHE_MAX_SIZE)
        {
            filesList.OrderBy(z => z, new FileInfoAccessTimeComparer()).TakeWhile(z => directorySize > CACHE_MAX_SIZE * 0.75)
                .ForEach(z =>
                {
                    z.Delete();
                    directorySize -= z.Length;
                });
        }
        filesList = null;
    }
    Thread.Sleep(CACHE_CLEANUP_INTERVAL);
}

注意要像我一样使用ForEach,你需要安装MoreLINQ。如果这是一个问题,请改用 foreach 循环。