16

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

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

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

BlockingCollection<byte[]> segments = new BlockingCollection<byte[]>(8);
// producer:
segments.Add(buffer);
// consumer:
byte[] buffer = _segments.Take();

如何避免托管内存碎片?

4

3 回答 3

10

您可能遇到了大对象堆问题 - 大于 85,000 字节的对象被放在未压缩的大对象堆上,这可能导致奇怪的内存不足情况。尽管.NET 4 中的性能显然得到了改进,但它远非完美。解决方案是基本上使用您自己的缓冲池,其中包含一些静态分配的内存块并重用它们。
关于 SO 有很多问题。

更新:Microsoft 提供了一个缓冲区管理器作为 WCF 堆栈的一部分。在 codeproject 上也有一个。

于 2011-04-17T21:00:12.350 回答
4

你的 byte[] 数组有多长?它们属于小对象还是大对象堆?如果您遇到内存碎片,我会说它们属于 LOH。

因此,您应该重用相同的字节数组(使用池)或使用更小的块。LOH 永远不会被压缩,因此它会变得非常分散。可悲的是,没有办法解决这个问题。(除了知道这个限制并避免它)

于 2011-04-17T21:03:07.433 回答
0

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

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
于 2018-06-03T04:44:56.003 回答