C# 使用字节数组时的堆碎片

C# 使用字节数组时的堆碎片,c#,bytearray,large-object-heap,memory-fragmentation,C#,Bytearray,Large Object Heap,Memory Fragmentation,我有一个C#4.0应用程序(单生产者/单消费者),它以块的形式传输大量数据。虽然没有新的内存分配,但过了一段时间内存就用完了 我使用Redgate内存分析器分析了内存,那里有很多可用内存。它说,由于碎片,空闲内存无法使用 我使用块集合作为缓冲区,字节数组作为成员: BlockingCollection<byte[]> segments = new BlockingCollection<byte[]>(8); // producer: segments.Add(buffer

我有一个C#4.0应用程序(单生产者/单消费者),它以块的形式传输大量数据。虽然没有新的内存分配,但过了一段时间内存就用完了

我使用Redgate内存分析器分析了内存,那里有很多可用内存。它说,由于碎片,空闲内存无法使用

我使用块集合作为缓冲区,字节数组作为成员:

BlockingCollection<byte[]> segments = new BlockingCollection<byte[]>(8);
// producer:
segments.Add(buffer);
// consumer:
byte[] buffer = _segments.Take();
BlockingCollection段=新的BlockingCollection(8);
//制作人:
段。添加(缓冲区);
//消费者:
字节[]缓冲区=_段。Take();

如何避免托管内存碎片?

您可能遇到了大型对象堆问题-大于85000字节的对象被放在大型对象堆上,而大型对象堆没有被压缩,这可能会导致奇怪的内存不足情况。尽管.NET4中的性能明显有所提高,但它还远远不够完美。解决方案基本上是使用您自己的缓冲池,其中包含一些静态分配的内存块,并重用它们。
围绕这一点有一大堆问题


更新:Microsoft提供了一个作为WCF堆栈一部分的。还有。

字节[]数组有多长?它们属于小对象还是大对象堆?如果你经历了记忆碎片,我会说它们会落入LOH


因此,应该重用相同的字节数组(使用池)或使用较小的块。LOH从未被压缩,因此它可能变得非常零碎。可悲的是,这是无法避免的。(除了知道并避免这个限制之外)

GC不会为您压缩大型对象堆,您仍然可以通过编程方式压缩它。下面的代码片段说明了如何实现这一点

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();

Chris是对的,另一个选择是使用小于85k的对象,这样它们就不会被分配到LOH上。微软的解决方案对我来说已经足够好了。因为它是抽象的,我应该实现我的。然后,我应该为数据传输程序的所有实例创建一个
静态
缓冲区管理器,还是为每个数据传输程序创建一个单例或一个实例成员(每个数据传输程序的寿命为2-3小时,其中有1000个,每个使用8x256 KB内存)为每个传输程序创建一个缓冲区管理器听起来像是将堆碎片问题转移到另一个地方(分配更大的内存块,然后再次释放)。您可以有一个缓冲区管理器池,但我会先使用singleton,看看它是否有任何问题。您可能可以设计它,使其隐藏在接口后面,每个传输程序都有自己的引用。然后,您可以轻松地在单实例和每个实例之间切换实现,或者根据您的喜好在两者之间切换。我使用了大约2-3小时和8x256 KB的内存分析器,内存分析器说它是一个大对象堆。如何创建字节数组池?(欢迎提供有用的链接)