什么是使用GC.AddMemoryPressure与非托管资源的呢?(What is the poi

2019-06-26 07:27发布

我读过关于在MSDN和通过C#CLR这个问题。

试想一下,我们有一个2MB的非托管HBITMAP分配和8个字节的管理位图指向它。 什么是讲述它的GC与AddMemoryPressure如果它永远不会成为能够使有关对象的任何东西,因为它是作为分配非托管资源,因此,不容易受到垃圾收集点?

Answer 1:

AddMemoryPressure的一点是要告诉垃圾回收有与该对象分配了大量的内存。 如果它是不受管理,垃圾收集器并不知道这件事; 只有管​​理部。 由于管理的部分比较小,GC可以让它通过垃圾收集几次,基本上是浪费内存,可能需要被释放。

是的,你还是要手动分配和释放的非托管内存。 你不能从脱身。 你只需要使用AddMemoryPressure以确保GC知道它的存在。

编辑:

那么,在一个情况下,我能做到这一点,但它会做没有什么大的区别,因为GC将不能够做我的类型的东西,如果我理解正确此:1)我要声明我的变量,8个字节管理,2MB非托管字节。 然后我会使用它,需要处理,所以非托管内存被释放。 现在它只会ocuppy 8个字节。 现在,我的眼睛,已经堪称beggining AddMemoryPressure和RemoveMemoryPressure末就不会取得什么不同。 什么我收到错了吗? 对不起,如此是烦人这一点。 - 豪尔赫·布兰科

我想我看到您的问题。

是的,如果你能保证你随时调用Dispose ,那么,你不需要用AddMemoryPressure和RemoveMemoryPressure打扰。 没有等价,由于基准仍然存在,类型永远不会被收集。

这就是说,你还是想用AddMemoryPressure和RemoveMemoryPressure,为了完整起见。 如果,例如,你的类的用户忘记调用Dispose? 在这种情况下,假设你实现的处置方式不当,你最终会在回收定稿非托管的字节,即收集管理对象时。 在这种情况下,你想要的内存压力仍然活跃,从而使物体更容易被回收。



Answer 2:

它提供,以便GC知道对象的收集过程中的真实成本。 如果对象是实际大于所管理的大小反映,它可能是快速(ER)收集的候选者。

布拉德·艾布拉姆斯进入它是相当清楚的:

想想看,有一个非常小的托管实例大小,但有一个指针指向一个非常大的一块非托管内存的一类。 即使在没有人引用管理实例,因为GC只看到管理实例的大小并不认为这是“值得”来释放实例它可以活下去了一会儿。 因此,我们需要“教”的GC这个实例的真实成本,使其准确地知道什么时候踢的集合释放的过程中更多的内存。



Answer 3:

这样说吧,仍然假设8个字节的管理对象每指的是2 MB的非托管的图像。 该GC可能要等待很长的时间收集小管对象的数百或数千之前,因为他们是如此之小。 这将意味着,也与2 MB的数百或数千个非托管块会活下去,等待拆除。 这可能会成为一个巨大的问题。 通过添加2 MB的内存压力,你会做GC构造认为,管理对象是不是8个字节的大,而是8个字节+ 2 MB。 这将触发早期收集的方式。

不要忘了删除通话。

当然,如果你自己处理,那么你将不再需要这一切。



Answer 4:

这些方法允许运行时有多少非托管内存正由进程分配一定意义。 而没有使用这些功能,也未必能够看到在这个过程中使用非托管内存的实际数量。

不过,我在这里其他的答案对于内存之间的关联不同意被提及和特定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收集早于它,否则,在努力避免耗尽内存。



文章来源: What is the point of using GC.AddMemoryPressure with an unmanaged resource?