GC经常触发这种情况是否正常?

时间:2016-02-22 10:28:48

标签: c# garbage-collection

今天我注意到我制作的一个小程序在程序生命的前10~20秒内经常触发GC。之后它再也几乎没有触发。 enter image description here

在这段时间内只运行一个功能,即下面的功能。获取~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在这段时间内经常触发这种情况是否正常?

2 个答案:

答案 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可能会经常运行。如果你创建了一些大字符串,它会特别运行:你读入内存的文件有多大?