dev*_*ium 14 .net c# vb.net garbage-collection
我已经通过c#在MSDN和CLR上阅读了这个问题.
想象一下,我们分配了一个2Mb的非托管HBITMAP和一个指向它的8字节托管位图.使用AddMemoryPressure告诉GC有什么意义,如果它永远无法对该对象做任何事情,因为它被分配为非托管资源,因此不易受垃圾收集的影响?
Ste*_*ons 12
提供它以便GC在收集期间知道对象的真实成本.如果对象实际上大于托管大小反映的对象,则它可能是快速(呃)收集的候选对象.
Brad Abrams 关于它的条目很清楚:
考虑一个具有非常小的托管实例大小但是拥有指向非常大的非托管内存块的指针的类.即使没有人引用托管实例,它也可以保持活动一段时间,因为GC只看到托管实例大小,它认为释放实例并不"值得".所以我们需要"教"GC关于这个实例的真实成本,这样它就能准确地知道何时踢出一个集合来释放更多的内存.
AddMemoryPressure的目的是告诉垃圾收集器,该对象分配了大量内存.如果没有管理,垃圾收集器就不知道了; 只有管理部分.由于托管部分相对较小,因此GC可能会多次通过垃圾回收,实质上浪费了可能需要释放的内存.
是的,您仍然需要手动分配和取消分配非托管内存.你无法摆脱这种局面.您只需使用AddMemoryPressure来确保GC知道它在那里.
编辑:
好吧,在第一种情况下,我可以做到,但它没有什么大的区别,因为GC无法对我的类型做任何事情,如果我理解正确:1)我声明我的变量,8个托管字节,2mb非托管字节.我然后使用它,调用dispose,因此释放了非托管内存.现在它只会占用8个字节.现在,在我看来,最后调用AddMemoryPressure和RemoveMemoryPressure并不会产生任何不同.我错了什么?很抱歉这对此很讨厌. - 豪尔赫布兰科
我想我看到了你的问题.
是的,如果你可以保证你总是打电话Dispose,那么是的,你不需要打扰AddMemoryPressure和RemoveMemoryPressure.没有等价,因为引用仍然存在,并且永远不会收集类型.
也就是说,为了完整起见,您仍然希望使用AddMemoryPressure和RemoveMemoryPressure.例如,如果您班级的用户忘记拨打Dispose,该怎么办?在这种情况下,假设您正确实现了Disposal模式,您将最终在完成时回收您的非托管字节,即收集托管对象时.在这种情况下,您希望内存压力仍然有效,以便更有可能回收对象.
这些方法使运行时能够了解进程正在分配多少非托管内存。如果不调用这些函数,它可能无法看到进程内使用的非托管内存的真实数量。
\n\n然而,我不同意这里关于所引用的内存和特定 GC 对象之间的关联的其他答案。
\n\n考虑:
\n\nvar buffer = IntPtr.Zero;\ntry\n{\n buffer = Marshal.AllocHGlobal(size);\n GC.AddMemoryPressure(size);\n\n // ... use buffer ...\n}\nfinally\n{\n Marshal.FreeHGlobal(buffer);\n GC.RemoveMemoryPressure(size);\n}\nRun Code Online (Sandbox Code Playgroud)\n\nGC 无法将 分配size给特定对象。该代码甚至可以存在于静态方法中。
因此我断言我们需要 \xe2\x80\x9cteach\xe2\x80\x9d 声明 GC 有关此实例的真实成本,以便它准确地知道何时启动收集以释放进程中的更多内存是不正确且具有误导性的。
\n\n相反,此方法可能会导致 GC 比其他方式更早进行收集,以避免内存不足。
\n| 归档时间: |
|
| 查看次数: |
8078 次 |
| 最近记录: |