【问题标题】:Is it normal for GC to trigger this often?GC经常触发这个正常吗?
【发布时间】:2016-02-22 10:28:47
【问题描述】:

今天我注意到我制作的一个小程序在程序生命周期的前 10~20 秒内经常触发 GC。之后它几乎不会再次触发。

在此期间仅运行 1 个函数,即以下函数。获取约 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经常触发这个正常吗?

【问题讨论】:

  • 它会导致性能下降吗?
  • 你操作的字符串有多长?
  • @dotctor 强制 gc 关闭可节省约 2 秒。所以是的。
  • @TheodorosChatzigiannakis 文件路径,

标签: c# garbage-collection


【解决方案1】:

嗯,是的。您正在创建大量生命周期较短的对象,并且这些对象会尽快处理掉。

尽量不要读取整个文件。相反,只需get the FileInfo to get the file size

这里你列举了两次目录列表,这也是不必要的:

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"

在此处使用StringBuilderstring.Format,并尝试在前面做尽可能多的事情。

【讨论】:

  • 不读取整个文件,而是使用 FileInfo 将其减少到仅 3 个 GC。谢谢。
【解决方案2】:

你真的不需要为了找到它的长度而读入整个文件。只需: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 可能会经常运行。如果您创建一些大字符串,它会特别运行:您正在读入内存的那些文件有多大?

【讨论】:

    猜你喜欢
    • 2013-01-10
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多