今天我注意到我制作的一个小程序在程序生命的前10~20秒内经常触发GC。之后它再也几乎没有触发。
在这段时间内只运行一个功能,即下面的功能。获取~2k的文件路径,并过滤掉大部分文件路径。
public static string[] FilterFiles(string path)
{
// Fetch the files from given directory
var files = Directory.GetFiles(path);
// Delete all files that are to small
foreach (string file in files)
{
string fullFile = default(string);
try
{
fullFile = File.ReadAllText(file);
}
catch
{
continue;
}
if (fullFile.Length < Settings.MinimumFileSize)
{
File.Delete(file);
}
}
// Obtain the new list without the small files
List<string> cleanFiles = new List<string>(Directory.GetFiles(path));
List<string> cleanReturn = new List<string>(Directory.GetFiles(path));
// Remove files we have handled before
foreach (string file in cleanFiles)
{
if (File.Exists(Settings.ExtractFolder + "\\" + file.Substring(file.LastIndexOf('\\') + 1) + "_Extract.xml"))
{
cleanReturn.Remove(file);
}
}
return cleanReturn.ToArray();
}
GC在这段时间内经常触发这种情况是否正常?
答案 0 :(得分:7)
嗯,是的。您正在创建大量具有较短生命周期的对象,并且这些对象会尽快处理。
尽量不要阅读整个文件。相反,只需get the FileInfo
to get the file size。
这里列举两次目录列表,这也是不必要的:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>default-test</id>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId><!-- group id of your plugin --></groupId>
<artifactId><!-- artifact id of your plugin --></artifactId>
<version><!-- version --></version>
<executions>
<execution>
<id>create-db</id>
<phase>test</phase>
<goals>
<goal><!-- your goal --></goal>
</goals>
<!-- add configuration -->
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId><!-- group id of your plugin --></groupId>
<artifactId><!-- artifact id of your plugin --></artifactId>
<version><!-- version --></version>
<executions>
<execution>
<id>drop-db</id>
<phase>test</phase>
<goals>
<goal><!-- your goal --></goal>
</goals>
<!-- add configuration -->
</execution>
</executions>
</plugin>
此外,由于字符串连接,会创建大量字符串:
List<string> cleanFiles = new List<string>(Directory.GetFiles(path));
List<string> cleanReturn = new List<string>(Directory.GetFiles(path));
在那里使用Settings.ExtractFolder + "\\" + file.Substring(file.LastIndexOf('\\') + 1) + "_Extract.xml"
或StringBuilder
,并尝试尽可能多地做。
答案 1 :(得分:1)
你真的不需要读取整个文件只是为了找到它的长度。只需:long length = new FileInfo(file).Length;
。
您可以使用Directory.EnumerateFiles(path)
枚举文件,而无需将所有文件名都读入数组中。
我认为您可以像这样重写整个函数:
public static IEnumerable<string> FilterFiles(string path)
{
foreach (string file in Directory.EnumerateFiles(path))
{
if (new FileInfo(file).Length < Settings.MinimumFileSize)
File.Delete(file);
else if (!File.Exists(Settings.ExtractFolder + "\\" + file.Substring(file.LastIndexOf('\\') + 1) + "_Extract.xml"))
yield return file;
}
}
然后使用foreach
枚举所有文件,如:
foreach (string file in FilterFiles(myPath))
...
或者,如果您要在应用其余逻辑之前强制删除所有小文件,请先在ToArray()
之前使用foreach
:
foreach (string file in FilterFiles(myPath).ToArray())
...
但回答你的问题:是的,如果你创建了很多小对象,GC可能会经常运行。如果你创建了一些大字符串,它会特别运行:你读入内存的文件有多大?