【发布时间】:2009-07-19 03:36:26
【问题描述】:
我在 MSDN 和 CLR 上通过 c# 阅读了有关此问题的信息。
假设我们分配了一个 2Mb 的非托管 HBITMAP 和一个指向它的 8 字节托管位图。如果它永远无法对对象进行任何处理,因为它被分配为非托管资源,因此不易受到垃圾回收的影响,使用 AddMemoryPressure 告诉 GC 有什么意义?
【问题讨论】:
标签: c# .net vb.net garbage-collection
我在 MSDN 和 CLR 上通过 c# 阅读了有关此问题的信息。
假设我们分配了一个 2Mb 的非托管 HBITMAP 和一个指向它的 8 字节托管位图。如果它永远无法对对象进行任何处理,因为它被分配为非托管资源,因此不易受到垃圾回收的影响,使用 AddMemoryPressure 告诉 GC 有什么意义?
【问题讨论】:
标签: c# .net vb.net garbage-collection
提供它是为了让 GC 在收集期间知道对象的真实成本。如果对象实际上比托管大小反映的要大,则它可能是快速(更)收集的候选对象。
Brad Abrams entry 非常清楚:
考虑一个有一个非常小的类 托管实例大小,但拥有 指向一个非常大的块的指针 非托管内存。即使在没有人之后 正在引用它的托管实例 可以活一段时间因为 GC 只看到托管实例 尺寸它认为它不“值得” 它”来释放实例。所以我们需要 “教导” GC 真正的成本 这个实例,以便它会 准确地知道什么时候踢 收集以释放更多内存 过程。
【讨论】:
AddMemoryPressure 的目的是告诉垃圾收集器该对象分配了大量内存。如果它是非托管的,垃圾收集器不知道它;只有托管部分。由于托管部分相对较小,GC 可能会让它多次通过垃圾收集,实际上浪费了可能需要释放的内存。
是的,您仍然需要手动分配和解除分配非托管内存。你无法摆脱它。您只需使用 AddMemoryPressure 来确保 GC 知道它的存在。
编辑:
好吧,以防万一,我可以做到,但这没什么大不了的,因为如果我理解正确,GC 将无法对我的类型做任何事情:1)我会声明我的变量,8 个托管字节,2mb 非托管字节。然后我会使用它,调用 dispose,这样非托管内存就被释放了。现在它只会占用 8 个字节。现在,在我看来,在最后调用了开头的 AddMemoryPressure 和 RemoveMemoryPressure 并没有什么不同。我怎么了?很抱歉对此感到如此恼火。 -- Jorge Branco
我想我看到了你的问题。
是的,如果你能保证你总是调用Dispose,那么是的,你不需要为 AddMemoryPressure 和 RemoveMemoryPressure 操心。没有等价性,因为引用仍然存在并且永远不会收集该类型。
也就是说,为了完整起见,您仍想使用 AddMemoryPressure 和 RemoveMemoryPressure。例如,如果您班级的用户忘记调用 Dispose 怎么办?在这种情况下,假设您正确地实现了 Disposal 模式,您最终将在完成时回收非托管字节,即在收集托管对象时。在这种情况下,您希望内存压力仍然处于活动状态,以便更有可能回收对象。
【讨论】:
这些方法允许运行时了解进程分配了多少非托管内存。如果不调用这些函数,它可能无法看到进程中正在使用的真实非托管内存量。
但是我不同意这里关于被引用的内存和特定 GC 对象之间的关联的其他答案。
考虑:
var buffer = IntPtr.Zero;
try
{
buffer = Marshal.AllocHGlobal(size);
GC.AddMemoryPressure(size);
// ... use buffer ...
}
finally
{
Marshal.FreeHGlobal(buffer);
GC.RemoveMemoryPressure(size);
}
GC 无法将size 分配给特定对象。这段代码甚至可以存在于静态方法中。
因此,我断言声明我们需要“教导”GC 这个实例的真实成本,以便它准确地知道何时启动一个集合以释放进程中的更多内存 不正确且具有误导性。
相反,此方法可能会导致 GC 比其他方法更早收集,以避免内存不足。
【讨论】:
这样说,仍然假设每个 8 字节的托管对象都引用一个 2 MB 的非托管图像。 GC 可能会等待很长时间才能收集成百上千个小的托管对象,因为它们太小了。这意味着成百上千个链接的 2 MB 非托管块也将保持活动状态,等待删除。这可能会成为一个大问题。通过在构造函数中添加 2 MB 的内存压力,您将使 GC 认为托管对象不是 8 字节大,而是 8 字节 + 2 MB。这将更早地触发收集方式。
不要忘记 Remove 调用。
当然,如果你放弃自己,那么你就不需要所有这些了。
【讨论】: