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

时间:2018-06-15 13:03:25

标签: c# heap-memory large-files

我正在运行一个简单的线程来清理目录中的一些缓存文件。大多数文件都是80KB以上的大对象。目录中大约有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();

1 个答案:

答案 0 :(得分:1)

没有大对象堆问题,因为您的基础数组很小(只有几千个条目)并且您的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循环。