【问题标题】:When is memory, allocated by .NET process, released back to Windows由 .NET 进程分配的内存何时释放回 Windows
【发布时间】:2011-07-11 19:50:06
【问题描述】:

设置

.NET 为每一代的堆(0、1、2、LOH)分段分配内存以获得连续的内存块,在启动时以及在收集后尝试满足分配请求时。

为每个堆分配的内存可能会随着应用程序“热身”而趋于平稳,除了可能用于第 2 代和大型对象堆。在垃圾回收期间,每个堆 (0, 1, 2) 都会被清扫和压缩,但大对象堆 (LOH) 除外,它只是被清扫。

我理解集合的“扫描”部分意味着 GC 识别哪些对象不再是根对象并且可用于收集(或终结),并且“紧凑”意味着在堆中仍然存在的地址被重新组织,以便可用的剩余堆具有更多可用的连续内存。

当超出堆内每个段的预算时,.NET 将分配另一个段以尽可能满足分配。

问题

我的问题归结为每个堆中的内存会发生什么,即 不再被应用程序使用(已提交),但仍由 .NET 保留? 什么时候发布回操作系统?

我认为这是一个进程可能会消耗大量内存(虚拟大小很大,但私有字节很小),但在检查其堆时大部分是可用空间。作为另一个警告,堆的总大小也可能非常小,并且不考虑进程消耗的内存。

没有阻塞的终结器,并且所有进程看起来都很健康 - 它可能在触发监视器警报之前已经运行了数周(例如)。

为了进一步澄清问题,如果您阅读 Tess .NET Memory Management - A Restaurant Analogy,如果桌子是堆段,餐厅是否会丢失桌子(例如空闲堆段)?

编辑

  1. 删除了对工作集和鸡的混淆参考
  2. 添加了对 Tess 餐厅类比的参考

【问题讨论】:

  • 我认为最小化不会要求任何人提供任何保留的内存(如果有时确实会发生这种情况)。据我所知,最小化只会导致 Windows 更愿意将该进程的内存交换到磁盘。
  • 查看此站点:informit.com/articles/article.aspx?p=100597 "这称为非确定性终结器 — 您无法确定何时调用对象的终结器。结果是您的对象使用的任何内存或非托管资源仍处于分配状态在对象本身不再被您的程序实际使用之后的不确定时间内。"
  • @Martinho,Winform 可能挂钩最小化消息并调用 GC.Collect(),我不知道,但它可以。
  • @Ian:那不会是 Windows 要求任何东西。那将是您自己的进程决定压缩堆,从而为您的进程保留更多未使用的内存。即使该内存是“免费的”,它仍然属于您的进程,而不是操作系统。问题不在于何时发生垃圾收集,而在于垃圾收集器“释放”的内存何时返回给操作系统。
  • @Martinho - 你说得对,我(错误)记得的是进程“工作集”报告受到最小化应用程序的影响。

标签: .net windows garbage-collection memory-management


【解决方案1】:

我的回答是——没关系。操作系统为应用程序(在其中运行 .NET 运行时)提供虚拟内存。这不是“真实”的记忆。操作系统可以将虚拟内存的每一页放在任何它喜欢的地方——在处理器上、在主内存中、在磁盘上。因此,应用程序使用的内存可能超过系统上的 RAM 量,并且操作系统会将所需的位复制到磁盘或从磁盘复制以确保应用程序继续运行(以某些寻址和技术限制为模)。

操作系统管理系统上所有进程的虚拟内存,并确保一个程序不会占用系统上的所有 RAM 以损害其他程序。当 .NET 运行时向系统请求在堆中使用的内存,但随后没有使用它时,该内存将(如果系统的可用 RAM 不足)被移动到磁盘,因为它没有被访问.

来自Tess 的电子邮件澄清:(强调我的)

段大小在整个申请过程中保持不变,但这里有两点需要考虑。

  1. 段的分配是虚拟分配,这意味着虽然我们保留虚拟内存,但我们只提交我们的实际使用,因此用于段的 私有字节 与段大小不同,这意味着在 GC 之后,您的私有字节将下降,而您的虚拟字节将保持不变。

  2. 当一个段不再使用时,即如果你碰巧对一个段中的所有内容进行 GC,使其不再包含任何 .net 对象,则将虚拟分配返回给操作系统。强>

相信这一点,堆段(餐厅表)将返回给操作系统。

【讨论】:

  • 虽然我大体上同意,尤其是关于“无关紧要”部分,但这种行为确实会影响一些事情:交换文件有多大。
  • 我家的硬盘是1TB。几个额外的 MB,甚至 1GB 的交换文件,都无关紧要
  • thecoop:交换文件大小与大磁盘无关,但磁盘访问性能仍然可能是一个问题 - 所以更快(更智能)释放内存,然后更小的交换文件对性能更好跨度>
  • 我碰巧在一个 5 GB 分区上运行带有交换文件的系统。交换文件增加 1GB 很重要。就像 RAM 一样,交换空间也不是取之不尽的资源。这很少有关系,这不是您应该在应用程序中担心的事情,但说它“不会真正影响任何事情”并不完全正确。
  • @thecoop - 我从 Tess 的带外电子邮件中添加了 cmets,以澄清您的答案。如果这不合适,请告诉我。
【解决方案2】:

我不知道这个问题的答案,但我怀疑 .NET 在进程退出之前不会释放它的堆(猜测可能是在卸载 AppDomain 时)。这仅基于我观察 perfmon .NET 内存计数器。 GC 总字节数计数器显示,至少在我的应用程序中,保留字节数在我的应用程序生命周期内会上下浮动,大约 30MB。

而且,如果 GC 在服务器模式下运行,也许 .NET 会更频繁地释放内存。

【讨论】:

    猜你喜欢
    • 2020-07-16
    • 2012-01-16
    • 2019-01-21
    • 2011-12-09
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    相关资源
    最近更新 更多