我有一个c# 4.0应用程序(单个生产者/单个消费者),它以块的形式传输大量数据。虽然没有新的内存分配,但我很快就用完内存了。
我使用Redgate内存分析器分析内存,那里有很多空闲内存。它说空闲内存不能使用,因为碎片。
我使用阻塞集合作为缓冲区,字节数组作为成员:
BlockingCollection<byte[]> segments = new BlockingCollection<byte[]>(8);
// producer:
segments.Add(buffer);
// consumer:
byte[] buffer = _segments.Take();
如何避免托管内存碎片?
您可能遇到了大对象堆问题—大于85,000字节的对象被放在未压缩的大对象堆上,这可能导致奇怪的内存不足情况。虽然。net 4的性能得到了明显的改进,但还远远不够完美。解决方案基本上是使用你自己的缓冲池,其中包含一些静态分配的内存块并重用它们。
SO上有一大堆关于这个的问题。
Update:微软提供了一个缓冲区管理器作为WCF栈的一部分。还有一个是关于codeproject的
你的byte[]数组有多长?它们属于小对象堆还是大对象堆?如果您遇到内存碎片,我会说它们属于LOH。
因此,您应该重用相同的字节数组(使用池)或使用较小的块。LOH从来没有被压缩过,所以它会变得非常破碎。可悲的是,这是没有办法的。(除了知道这个限制并避免它)GC不会为您压缩大型对象堆,您仍然可以通过编程方式压缩它。下面的代码片段说明了如何实现这一点。
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();