【问题标题】:where is leak in my code?我的代码在哪里泄漏?
【发布时间】:2009-05-18 11:52:41
【问题描述】:

这是我的代码,它打开一个 XML 文件 (old.xml)、过滤无效字符并写入另一个 XML 文件 (abc.xml)。最后,我将再次加载 XML (abc.xml)。执行以下行时,出现异常说xml文件被另一个进程使用,

xDoc.Load("C:\\abc.xml");

有没有人知道什么是错的?我的代码中是否有任何泄漏以及原因(我一直在使用“using”关键字,对看到泄漏感到困惑......)?

这是我的全部代码,我在 Windows Vista x64 下使用 C# + VSTS 2008。

    // Create an instance of StreamReader to read from a file.
    // The using statement also closes the StreamReader.
    Encoding encoding = Encoding.GetEncoding("utf-8", new EncoderReplacementFallback(String.Empty), new DecoderReplacementFallback(String.Empty));
    using (TextWriter writer = new StreamWriter(new FileStream("C:\\abc.xml", FileMode.Create), Encoding.UTF8))
    {
        using (StreamReader sr = new StreamReader(
            "C:\\old.xml",
            encoding
            ))
        {
            int bufferSize = 10 * 1024 * 1024; //could be anything
            char[] buffer = new char[bufferSize];
            // Read from the file until the end of the file is reached.
            int actualsize = sr.Read(buffer, 0, bufferSize);
            writer.Write(buffer, 0, actualsize);
            while (actualsize > 0)
            {
                actualsize = sr.Read(buffer, 0, bufferSize);
                writer.Write(buffer, 0, actualsize);
            }
        }
    }

    try
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load("C:\\abc.xml");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

EDIT1:我尝试将缓冲区的大小从 10M 更改为 1M,它可以工作!我很困惑,有什么想法吗?

EDIT2:当输入的旧 XML 文件非常大(例如 100M 之类)时,我发现这个问题很容易重现。我怀疑它是否是.Net 已知的错误?我将使用 ProcessExplorer/ProcessMonitor 之类的工具来查看哪个进程锁定了文件以防止 XmlDocument.Load 访问它。

【问题讨论】:

  • 为什么缓冲区这么大? (虽然它不应该与问题有关,但知道为什么 10Mb 会很有趣......)。我可能会使用 10k,也许......
  • 我尝试将缓冲区的大小从 10M 更改为 1M,它可以工作!我很困惑,有什么想法吗?
  • 我在原始代码中使用大缓冲区纯粹是为了测试目的,一个临时值,不是故意设置的。

标签: c# file memory-leaks


【解决方案1】:

这对我来说很好。 纯属猜测,但也许病毒检查器正在扫描文件? 要进行调查,请尝试禁用您的病毒检查程序并查看它是否有效(然后重新启用您的病毒检查程序)。

顺便说一句,它可以通过一种方式使文件保持打开状态:如果StreamReader 构造函数抛出异常;但是无论如何你都不会到达XmlDocument 的东西......但是考虑一下:

using (FileStream fs = new FileStream("C:\\abc.xml", FileMode.Create))
using (TextWriter writer = new StreamWriter(fs, Encoding.UTF8))
{
   ...
}

现在fs 被设置在new StreamWriter(...) 抛出的边缘情况中。但是,我确实相信这就是问题所在。

【讨论】:

  • 我尝试将缓冲区的大小从 10M 更改为 1M,它可以工作!我很困惑,有什么想法吗?
【解决方案2】:

您可能在根目录上运行 FileSystemWatcher?

您还可以使用 ProcessMonitor 查看谁访问了该文件。

【讨论】:

  • 文件系统监视程序?你什么意思?
  • 不,我没有明确使用该类,并且我已经发布了所有代码。我试图将缓冲区的大小从 10M 更改为 1M 并且它有效!我很困惑,有什么想法吗?
【解决方案3】:

问题是您的char[] 似乎太大了。如果它太大,它位于大对象堆上,而不是堆栈上。因此,只要软件正在运行,大对象堆就不会被压缩,曾经分配的空间可能不会再次使用 - 这看起来像内存泄漏。尝试将您的数组拆分为更小的块。

【讨论】:

  • 我承认缓冲区过大,但这与问题陈述“有异常说 xml 文件被另一个进程使用”有什么关系。缓冲区
  • 如果我使用较小的缓冲区大小,我已经尝试过,我的代码将毫无问题地运行。为什么过大的缓冲区会阻止我的文件被关闭?我认为我最初遇到的错误是文件未关闭?
  • 在这种情况下,+1 到 BeowulfOF;过大的缓冲区会导致这种情况似乎并不明显(实际上,我在本地没有遇到任何问题)......很好奇。 OutOfMemoryException,当然……但是文件锁定?很奇怪……
  • 大型对象堆与此有关的想法对我来说听起来像是迷信。大对象与 Gen 2 一起收集,但这无关紧要,因为缓冲区不包含对文件的引用 - 它只是一个 char[]。一定有一些外部因素在起作用。
  • 也许操作系统很重要?我正在使用 Windows Vista x64,使用 .Net 3.5 SP1。
【解决方案4】:

我赞同 Leppie 的建议,即使用 ProcessMonitor(或等效的)来确定谁在锁定文件。其他一切都只是猜测。

【讨论】:

    【解决方案5】:

    你的缓冲区没有被释放,是吗?

    【讨论】:

    • 我认为 CLR 管理所有内存缓冲区。使困惑。无论如何,您建议的解决方法是什么?请出示您的代码好吗?
    • 没有必要(实际上也没有机制)释放缓冲区; GC 很快就会拿走(可能在 GEN0,所以很便宜)。
    • 重点是,缓冲区对于堆栈来说太大了,所以它被打包到大对象堆上——只要进程正在运行,它就永远不会被压缩。
    • @BeowulfOF,你的解决方案是什么,你能出示你的代码吗?
    【解决方案6】:

    您是否检查过没有其他进程尝试访问该文件?

    【讨论】:

    • 我尝试将缓冲区的大小从 10M 更改为 1M,它可以工作!我很困惑,有什么想法吗?
    【解决方案7】:

    代码运行良好。刚刚检查过。

    【讨论】:

    • 奇怪,有什么想法可以进一步检查吗?
    • 不...我猜问题是由您的工作站引起的。代码有效,所以 - 只有水晶球可以帮助我帮助你。
    【解决方案8】:

    using 会调用Dispose,但Dispose 会在写入流上调用 close 吗?如果没有,系统可能仍然认为该文件已打开以供写入。

    我会尝试在其 using 块结束之前关闭 writer

    编辑:我自己也试了一下代码。编译并运行没有您看到的问题。尝试像其他人提到的那样关闭病毒扫描程序,并确保您没有打开文件的某个窗口。

    【讨论】:

    • Close() 是通过调用 Dispose() 实现的,关闭 StreamReader 或 StreamWriter 也会关闭底层流。所以这无济于事。
    【解决方案9】:

    它适用于某些人而不适用于其他人的事实使我认为该文件没有被关闭。在尝试加载文件之前关闭编写器。

    【讨论】:

    • 如果文件没有被关闭,它对任何人都不起作用!代码显示文件正在被关闭(至少在这个线程/进程的范围内)
    【解决方案10】:

    我敢打赌,您正在运行一些防病毒解决方案,它会在文件关闭后锁定文件。要验证,请尝试在加载文件之前添加延迟(例如 1 秒)。如果这样有效,您可能找到了原因。

    【讨论】:

      【解决方案11】:

      运行Process Explorer

      确保是你的程序首先锁定了文件。

      【讨论】:

        最近更新 更多