如何摆脱 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
循环。
我有一个简单的线程 运行 从目录中清除一些缓存文件。大多数文件是超过 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
循环。