File.ReadAllText导致内存泄漏

时间:2011-09-16 19:08:27

标签: c# delegates garbage-collection

  

可能重复:
  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();
          }));
    }

有没有人知道为什么会这样?我假设它与委托或处理程序有关。

2 个答案:

答案 0 :(得分:3)

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

GC需要时间,所以你要快速连续重复这个,那么在下一个GC之前你很可能会在内存中有几个文件。这看起来非常低效。您应该考虑使用stream based reader,以避免将所有数据保留在内存中。如果您确实使用了流阅读器,请确保之后dispose使用它,以避免引入其他泄漏。

另一件事是检查它是否未在某处订阅静态事件,从而阻止您的对象树被丢弃。它是一个网络应用程序吗?

答案 1 :(得分:2)

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

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

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

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

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

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

相关问题