我有一个应用程序跟踪日志文件。每次日志文件更新(通常是一行中的一系列更新)时,内存都会使用不受控制的气球。
我已经跟踪了这个电话的问题:
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();
}));
}
有没有人知道为什么会这样?我假设它与委托或处理程序有关。
答案 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字节)或者您搜索大对象堆安全文本框组件使用。