.NET可用内存使用情况(如何防止OS的内存/释放内存)

Ron*_*dau 17 .net c# clr garbage-collection memory-management

我目前正在开发一个大量使用缓存数据的网站,以避免往返.在启动时,我们得到一个"大"图(数百个不同类型的对象).这些对象通过WCF检索并反序列化(我们使用协议缓冲区进行序列化)我正在使用redgate的内存分析器来调试内存问题(在我们完成之后,内存似乎与我们应该需要的内存不相符"初始化并以此报告结束

全球报告

现在我们可以从这份报告中得到的结论是:

1)分配的大部分内存是免费的(它可能在反序列化期间被正确分配,但现在它是免费的,我希望它能够返回到操作系统)

2)内存碎片化(这很糟糕,因为每当我刷新现金时我需要重做内存饥饿的反序列化过程,这反过来会创建大对象,由于碎片而可能抛出OutOfMemoryException)

3)我不知道为什么空间是碎片的,因为当我看到大对象堆时,只有30个实例,15个object []直接连接到GC并且与我完全无关,1也是char数组直接附加到GC堆,其余15个是我的,但不是原因,因为如果我在代码中注释掉它,我得到相同的报告.

所以我的问题是,我该怎么做才能更进一步呢?我不太确定在调试/工具中要找什么,因为看起来我的内存是碎片化的,但不是我,并且.net分配了大量的可用空间,我无法释放.

另外请确保你在回答之前理解这个问题,我不是在寻找一种方法来释放.net(GC.Collect)中的内存,而是释放已经在.net中释放的内存,以及系统以及对记忆进行碎片整理.

请注意,缓慢的解决方案很好,如果可以手动对大堆进行碎片整理,那么我可以在RefreshCache的末尾调用它,如果运行需要1或2秒,则可以.

谢谢你的帮助!

我忘记了一些注意事项:1)该项目是.net 2.0网站,我在.net 4池中运行相同的结果,如果我在.net 4池中运行它并将其转换为.net 4和重新编译.

2)这些是发布版本的结果,因此调试版本不是问题.

3)这可能非常重要,我在webdev服务器上根本没有得到这些问题,只在IIS中,在webdev中,我的内存消耗量与我的实际消耗量相当接近(更多,但不是5-10倍! )

ata*_*mir 7

我知道这不是您想听到的答案,但是您无法将内存强制释放回操作系统。但是,您出于什么原因要这样做?一旦物理内存不足,.NET 会将其堆释放回操作系统。但如果有足够的空闲物理内存,.NET 将保留其堆,以便将来更快地分配对象。如果您真的想强制 .NET 将其堆释放回操作系统,我想您可以编写一个 C 程序,该程序只执行 malloc 直到内存耗尽。这应该会导致操作系统向 .NET 发出信号以释放其未使用的堆部分。

最好为 .NET 保留未使用的内存,以便您的应用程序具有更好的分配性能(因为运行时知道哪些内存是空闲的,哪些不是,分配可以只使用空闲内存,而无需通过系统调用操作系统来获取更多内存)。

垃圾收集器负责对堆进行碎片整理。每隔一段时间(通常在收集运行期间),如果它确定需要这样做,它就会在堆周围移动对象。(这就是 C++/CLI 具有用于“固定”对象的 pin_ptr 构造的原因)。

尽管内存碎片化通常不是什么大问题,因为它提供了快速的随机访问。

至于您的 OutOfMemoryException,我没有很好的答案。通常我会怀疑你的旧对象图没有被收集(某处的某个对象持有对它的引用,“内存泄漏”)。但是由于您使用的是分析器,所以我不知道。


Ben*_*nor 7

在大对象堆上分配的对象(对象> = 85,000字节,通常是数组)不会被垃圾收集器压缩.微软决定移动这些对象的成本太高.

建议尽可能重用大对象,以避免托管堆和VM空间上的碎片.

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

我假设您的大对象是由反序列化库创建的临时字节数组.如果库允许您提供自己的字节数组,则可以在程序开始时预先分配它们,然后重用它们.