如何释放占用的内存

Lef*_*nis 3 .net c# vb.net windows winforms

我的项目中有一个主窗口,主要内部有许多其他儿童寡妇.
我注意到.当我打开主窗口占用1500K的内存时,打开一个子窗口然后添加占用内存6000K.
当我打开第二个窗口做同样的事情.当我关闭两个子窗口时,占用的内存不会被释放.
所以我想要的是在关闭子窗口时释放占用的内存.
我怎么能这样做?
如果有可能,请在vb.net中向我提供一些代码示例.
这个问题经常在本地NET上的计算机中找不到,而不是在我的计算机上(开发人员计算机上有SQL服务器).

Cod*_*ray 13

这个问题的其他一些答案包含令人失望的错误信息量,而其他问题则使问题过于复杂.关于.NET中的垃圾收集存在很多误解,而这里所提出的理论肯定没有帮助解决问题.

首先,使用Windows任务管理器分析内存使用情况是一个巨大的错误.您将收到严重无效的信息,并且尝试根据此信息修改您的应用程序只会使事情变得更糟,而不是更好.如果您怀疑自己遇到了性能问题(而且大多数应用程序实际上都会遇到任何问题,那就非常值得怀疑),您需要投资一个合适的内存分析器并使用它.

其次,垃圾收集的重点是你不必担心这种事情.而且不只是你不担心,但你不应该担心,无论是.在编写面向.NET Framework的应用程序时,您不应该执行或尝试任何类型的手动内存管理.抵制垃圾收集器内部工作的诱惑,当有人告诉您GC.Collect手动调用以强制进行垃圾收集时,将手指牢牢地植入耳中.我想我不应该永远不说,但几乎没有理由这样做.我更可能怀疑手动调用垃圾收集的代码而不是其他任何东西.

为什么不应该手动调用垃圾回收?好吧,除了显而易见的论点,它首先打破了使用托管语言的全部要点,这是因为垃圾收集是一个非常缓慢而昂贵的过程.您希望它尽可能地运行以保持最佳性能.幸运的是,实现垃圾收集算法的程序员比你或我更聪明,更有经验:他们将其设计为仅在必要时运行,并且不会更频繁地运行.你不会看到更频繁地运行它的优势,但你看到一个缺点.作为程序员,这应该是完全不透明的.

唯一的例外是当您使用非托管对象时,这些对象不会被垃圾收集器收集或管理.您将能够识别这些对象,因为它们都实现了IDisposable接口,该接口提供了Dispose释放非托管资源的方法.在公开此方法的对象上,您应该在完成对象使用后立即调用它.或者更好的是,在using语句中包装对象的声明和使用,无论发生什么情况,都会自动处理对象的处理(例如,即使在使用对象的代码中抛出异常).

当然,您会注意到Windows窗体库中的几个标准对象实现了该IDisposable方法.例如,普遍存在的Form提供了一种Dispose方法.但是,这并不一定意味着您负责手动处理这些对象.通常,您只需要显式调用Dispose您明确创建的对象的方法 - 容易记住,对吧?Framework自动创建的对象也会自动销毁.例如,您Form在设计时放置在对象上的控件会在放置容器表单时自动处理.和Form对象时,他们关闭自己的自动配置.这与您的问题中提出的问题特别相关.该方法文档Form.Close告诉我们:

关闭表单时,将关闭对象中创建的所有资源并处理表单.

[...]

未处置表单时的两个条件Close是(1)它是多文档界面(MDI)应用程序的一部分,并且表单不可见; (2)您已使用表格显示ShowDialog.在这些情况下,您需要Dispose手动调用以标记所有表单的垃圾收集控件.

请注意,一般情况下,您不会发现自己Form.Dispose需要从代码中手动调用.当用户的MDI父窗口不可见时,用户无法关闭MDI子窗体,如果您的父窗口不可见时,您自己在代码中关闭窗体,则只需插入一个调用即可Form.Dispose.使用该ShowDialog方法将表单显示为模式对话框时,可以方便地将其创建包含在using语句中.

现在,回想一下,简单地Dispose在对象上调用该方法只会释放非托管资源,并将该对象标记为可用于垃圾回收.它不会立即释放该对象声明的内存.这很重要,因为它正是您对内存分析的尝试所关注的.你知道对象正在处理中,因为你提到变量对你来说是不可用的(你说你"失去了它们的价值").那是因为您无法访问已处置的对象.然而,这并不一定意味着他们声称的记忆已经完全释放.这样做是垃圾收集器的工作,我们已经建立了你不应该与之相关的垃圾收集器.它将等待释放内存,直到应用程序处于空闲状态,或者它迫切需要重用该内存.否则,它将推迟收集,这仍然可以.