【问题标题】:File.ReadAllText leading to memory leak [duplicate]File.ReadAllText 导致内存泄漏[重复]
【发布时间】:2011-09-16 19:08:26
【问题描述】:

可能重复:
TextBox.Text Leaking Memory in WPF Application

我有一个跟踪日志文件的应用程序。每次日志文件更新(通常是一系列连续更新)时,内存都会使用失控的气球。

我已经找到了这个电话的问题:

    if (File.Exists(Path + "\\logfile.txt"))
                Data = File.ReadAllText(Path + "\\logfile.txt");

这是从此处的 LoadAllData 中调用的。

    private void FileChangeNotificationHandler(object source, FileSystemEventArgs e)
    {
        this.Dispatcher.BeginInvoke
          (new Action(delegate()
          {
              Logfile.GetPath();
              Logfile.LoadAllData();

              LogText.Clear();
              LogText.Text = Logfile.Data;
              if (CheckFollowTail.IsChecked == true) LogText.ScrollToEnd();
          }));
    }

有没有人知道为什么会发生这种情况?我认为它与委托或处理程序有关。

【问题讨论】:

  • 那么,每次你的日志文件发生变化时,你会丢弃所有的内容并完全重新加载文件吗?
  • 我排除了文本框分配的问题。
  • 对,日志文件足够小。必要时我会提供更多情报。

标签: c# delegates garbage-collection


【解决方案1】:

这可能只是取决于您将日志文件数据加载到内存中的数量和频率。

GC 需要时间,因此如果您连续快速地重复此操作,那么在下一次 GC 之前,您可能会在内存中拥有多个文件价值的数据。这似乎非常低效。您应该考虑使用stream based reader,以避免将所有数据保留在内存中。如果您确实使用了流阅读器,请确保您事后对其进行dispose 以避免引入另一个泄漏。

检查它的另一件事是您没有在某处订阅静态事件,因此阻止您的对象树被处置。是网络应用吗?

【讨论】:

  • 一些 LOH 碎片也可能发生。
  • 感谢您的回复。这是一个桌面应用程序,WPF。我会试试流阅读器,看看会发生什么。
  • 确保你丢弃了流阅读器,否则你会再次泄漏。
【解决方案2】:

首先,检查文件是否存在是错误的。这是因为文件系统是volatile,并且不仅仅是存在在起作用(例如权限)。这样做的正确方法是只打开文件,然后在失败时处理异常。

现在,谈谈你所说的问题。我怀疑正在发生的事情是日志变得足够大以使用大对象堆(85000 字节就足够了,iirc,记住.Net 使用 utf16(2 字节)字符)。一个 43K 的 ascii 日志文件就是您开始引发问题所需的全部内容,因为在那个大小下,您的 .Net 字符串不再以正常方式进行垃圾收集。每次读取文件时,最终都会将整个日志文件的另一个实例添加到内存中。

为了最好地推荐如何解决这个问题,了解您为 LogText 变量使用的组件类型会很有帮助。但在获得这些信息之前,我至少可以提出一些建议:

理想情况下,您只需保持文件打开(使用FileShare.ReadWrite)并在每次收到更改通知时从流中读取。但这并不总是可能的。

如果您每次都必须重新打开文件,请至少逐行读取文本(使用 StreamReader),而不是使用 File.ReadAllLines() 一次全部读取。这将帮助您将日志文件分解为不会出现在大型对象堆中的较小部分。

不幸的是,我怀疑你最终会被困在构建一个大字符串以分配给纯文本框。如果是这种情况,我强烈建议您要么只构建并显示日志的最后一部分(小于 85000 字节),要么搜索大型对象堆安全文本框组件使用。

【讨论】:

  • 我不同意检查文件是否存在是错误的。您应该始终进行防御性编码以避免异常,它们很昂贵。是的,文件系统是易变的,仍然可能发生异常,但在这种情况下,它更有可能是边缘情况。使用异常来控制流程是错误的。
  • @TheCodeKing:MSFT 员工另有建议......请参阅我之前的评论。
  • @TheCode - 这不仅仅是删除风险,还有权限(文件可能存在,但您无权读取)和共享(您可能有权限,但它被锁定,因为别人开了)。这个特定的问题是后者的完美示例,因为有很多日志写入器会在写入日志文件时锁定日志文件,并且已知写入是分批进行的.因为无论如何你都需要一个好的异常处理程序,所以 File.Exists 检查是浪费的,并且会导致错误的安全感。
  • 是的,完全不相信。 File.Exists 仅在您有权访问该文件时才返回 true。我同意在某些情况下这可能是一个优势。
猜你喜欢
  • 2014-06-19
  • 2015-07-06
  • 2014-06-07
  • 2013-11-20
  • 2011-10-28
  • 2016-01-18
  • 2012-12-13
  • 1970-01-01
  • 2011-01-08
相关资源
最近更新 更多