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倍! )
我知道这不是您想听到的答案,但是您无法将内存强制释放回操作系统。但是,您出于什么原因要这样做?一旦物理内存不足,.NET 会将其堆释放回操作系统。但如果有足够的空闲物理内存,.NET 将保留其堆,以便将来更快地分配对象。如果您真的想强制 .NET 将其堆释放回操作系统,我想您可以编写一个 C 程序,该程序只执行 malloc 直到内存耗尽。这应该会导致操作系统向 .NET 发出信号以释放其未使用的堆部分。
最好为 .NET 保留未使用的内存,以便您的应用程序具有更好的分配性能(因为运行时知道哪些内存是空闲的,哪些不是,分配可以只使用空闲内存,而无需通过系统调用操作系统来获取更多内存)。
垃圾收集器负责对堆进行碎片整理。每隔一段时间(通常在收集运行期间),如果它确定需要这样做,它就会在堆周围移动对象。(这就是 C++/CLI 具有用于“固定”对象的 pin_ptr 构造的原因)。
尽管内存碎片化通常不是什么大问题,因为它提供了快速的随机访问。
至于您的 OutOfMemoryException,我没有很好的答案。通常我会怀疑你的旧对象图没有被收集(某处的某个对象持有对它的引用,“内存泄漏”)。但是由于您使用的是分析器,所以我不知道。
在大对象堆上分配的对象(对象> = 85,000字节,通常是数组)不会被垃圾收集器压缩.微软决定移动这些对象的成本太高.
建议尽可能重用大对象,以避免托管堆和VM空间上的碎片.
http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
我假设您的大对象是由反序列化库创建的临时字节数组.如果库允许您提供自己的字节数组,则可以在程序开始时预先分配它们,然后重用它们.