this.Dispose()在关闭窗体后不会释放窗体使用的内存。

12

我有一个Windows Form应用程序,点击某些按钮会在第二个窗体中创建对象。当用户关闭此第二个窗体时,该窗体使用的内存不会被释放(根据任务管理器)。

我尝试在退出按钮上使用this.dispose()this.close()form2 = null在主代码中,并尝试在处理之前通过代码清除该窗体的所有控件。 这些都没有起作用,每次用户单击该按钮时,应用程序的内存使用量增加,先前实例使用的内存不会被释放。

我应该使用什么来解决这个问题?


2
你也许正在寻找一种释放表单子对象分配的内存的方法?一个简单的表单类具有如此低的内存消耗,我无法想象会有人发帖讨论这个... - Adrian Grigore
4个回答

20

调用Dispose方法并不能清理对象使用的内存,Dispose通常用于运行用户定义的代码以释放不会自动释放的资源,例如文件句柄、网络句柄、数据库连接等。

最可能的原因是第二个窗体将事件附加到在其外部的对象(可能是第一个窗体?),并且从未取消附加。

如果在第二个窗体中有任何事件,请在OnClose覆盖中取消附加它们-这将使第二个窗体有资格进行垃圾回收。

请注意,.NET垃圾收集器非常不可预测,它可能在清理所有已有资格进行收集的旧实例之前创建几个对象实例。要确定(而不需要使用内存分析器),一种方法是在终结器中设置断点:

public class MyForm : Form {
  ~MyForm() {
    //breakpoint here
  }
}
如果终结器被调用,则该类是OK的,否则您仍会有泄漏。您还可以给GC“一脚”,但只用于故障排除目的 - 不要在生产中使用此代码 - 通过初始化GC:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

将上述代码放在某个在关闭和释放第二个表单之后运行的位置。您应该会在MyForm终结器中触发断点。


我按照这些建议去做了,但即使加入了GC代码,我的Form finalize函数仍然没有触发断点。看起来我有一个严重的内存泄漏问题。我在另一个带OpenGL的Form中使用OpenTK,也许是它引起的问题? - theJerm
这就是为什么我更喜欢C++的原因。 - Baso

3

Dispose方法并不是用来释放内存的,这是由公共语言运行时的垃圾回收器负责的。Dispose方法主要用于释放其他稀缺资源,例如数据库连接和文件句柄。

一般来说,在.NET应用程序中,您不需要担心内存消耗,因为框架会为您处理。如果您需要更精细的内存控制,则应该使用提供此控制的语言(如C ++)进行开发。


0

听起来好像内存仍在使用,因为已释放的对象尚未被垃圾回收器回收。尝试使用GC.Collect()静态方法强制进行垃圾回收。请注意性能问题,因为这通常会暂停程序直到完成。

GC.Collect();

0
不要调用Dispose()方法,而是调用——>>> Dispose(true),你会感到惊讶的。它实际上释放了内存,你可以在任务管理器中观察到效果。

1
Dispose() 调用 Dispose(true)。那是一个受保护的方法;你不应该调用它。 - SLaks
是的,它是受保护的,而不是私有的。因此没有理由不调用它。Dispose(bool disposing)在两种不同的情况下执行。如果disposing等于true,则该方法已被用户代码直接或间接调用。托管和非托管资源都可以被处理。如果disposing等于false,则该方法是由运行时从终结器内部调用的,您不应引用其他对象。只能处理非托管资源。© MSDN - Wallstrider
Dispose() 调用 Dispose(true)。内部方法是实现细节,不应直接调用。 - SLaks
这不是一个原因或官方限制。Dispose() 调用: Dispose(true); GC.SuppressFinalize(this);在这里,GC.SuppressFinalize(this) 是个问题,所以当你只调用 Dispose(true) 时,不会发生什么坏事情。所以如果它被限制了,可能会成为受保护的内部方法。 - Wallstrider
GC.SuppressFinalize()不是问题,它只是一种垃圾回收的优化。你需要了解dispose模式的工作原理。 - SLaks
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接