【发布时间】:2023-01-12 03:45:30
【问题描述】:
在我的 C# Winforms 应用程序中,我有以下内容(显示的代码最少)
Form1 是用户用来做事的主要应用程序。 Form2 显示了一个帮助文件,解释了如何使用 Form1 上的功能来做事。只要 Form1 可见,我希望用户能够随意显示(无模式)和关闭帮助文件。
我还担心用户打开和关闭 Form2 时可能发生的内存泄漏。因此,当用户关闭 Form2 时,它会引发 Form1 订阅的事件。当调用 Form1 事件方法时,它调用 Form2 上的 Dispose(),将 Form2 对象设置为 null 并调用垃圾收集器。
这会消除因用户打开和关闭 Form2 而导致的内存泄漏的可能性吗?是不是矫枉过正?是否有更好的方法确保在 Form2 关闭的时间点进行垃圾回收?我不想依赖 Windows 稍后决定这样做
更新
Jimi 指出我不需要 Form2 Closed 事件的自定义事件处理程序。他是对的。在我的 Form1 类中,我现在为我的 Form2 使用标准的 FormClosedEventHandler。然而,代码本身几乎保持不变。但是,当我删除对 GC.Collect() 的调用时,我看到了使用任务管理器内存泄漏的证据。
这是我的数据:
Run #1. Form2_FormClosed method has:
------------------------------------
f_HelpForm.Dispose();
f_HelpForm = null;
GC.Collect();
Start App
Task Manager Memory for app: 6.7 MB
Open and Close Form2 20 times
Task Manager Memory for app: 8.2 MB
Run #2. Form2_FormClosed method has:
------------------------------------
f_HelpForm.Dispose();
f_HelpForm = null;
//GC.Collect();
Start App
Task Manager Memory for app: 6.9 MB
Open and Close Form2 20 times
Task Manager Memory for app: 18.9 MB
Run #3. Form2_FormClosed method has:
------------------------------------
//f_HelpForm.Dispose();
f_HelpForm = null;
//GC.Collect();
Start App
Task Manager Memory for app: 6.9 MB
Open and Close Form2 20 times
Task Manager Memory for app: 18.1 M
在没有调用 GC.Collect() 的情况下,无论是否调用 Dispose(),与包含调用 GC.collect() 的代码相比,占用空间增加了 100%。
我听到你们在说什么,但是............我想我会把我的代码留在它的“运行#1”配置中
代码
注意:我承认设置 form2 = null 对幕后垃圾收集有直接影响。但是,我设置 form2 = null 的目的是向 Form2Button_Click 方法提供一个信号,它可以用来决定是否实例化一个 Form2 对象
public partial class Form1 : Form
{
Form2 form2;
public Form1()
{
form2 = null;
}
private void Form2Button_Click(object sender, EventArgs e)
{
if (form2 == null)
{
form2 = new ClsHelpForm(this);
form2.Form2Closed += Form2_FormClosed;
}
form2.Select();
form2.Show();
}
//When this user clicks the Help button on Form1, this method is invoked
private void Form2_FormClosed(object sender, EventArgs e)
{
form2.Form2Closed -= Form2_FormClosed;
form2.Dispose();
form2 = null;
GC.Collect();
}
{
public partial class Form2 : Form
{
public event EventHandler Form2Closed;
public Form2()
{
}
//When the user clicks the "X" button on Form2, this method is invoked
private void Form2_FormClosed(object sender, Form2EventArgs e)
{
Form2Closed?.Invoke(this, EventArgs.Empty);
}
}
【问题讨论】:
-
你根本不需要
public event EventHandler Form2Closed;,你可以在没有它的情况下订阅FormClosed事件。引发标准事件时删除 Form1 中的处理程序。仅此而已——您是否注意到在关闭 Form2 时使用分析器(例如诊断工具)未回收某些内存? --GC.Collect();没有任何目的:它要么可以收集可收集的东西,要么不能。如果可以,它会在需要时执行。 -
强制 GC 永远不会修复“内存泄漏”(从技术上讲,这在纯 C# 安全代码中不存在)...您可能正在谈论某种长期存在的引用,这些引用也不会被 GC 清除。
-
@cj.burrow @Jimi:我同意我不需要自定义事件处理程序。在我的 Form1 课程中,我现在为我的 Form2 使用标准的
FormClosedEventHandler。但是,当我删除对GC.Collect()的调用时,我看到了使用任务管理器内存泄漏的证据。我会尽快用我的发现更新我的问题 -
您不应该使用 Taskmanager 进行分析。它可能有助于大规模比较资源使用情况与其他进程,但仅此而已。如果您怀疑存在泄漏之类的问题,请使用真正的探查器,例如 Visual Studio 中可用的诊断工具。
标签: c# winforms garbage-collection non-modal