0

我有一种情况,我分配了大量内存,但在许多较小的子阵列中。我注意到,一旦我通过每个数组大约 85,000 字节的阈值,性能就会明显变差。我假设性能下降是因为较小的数组被分配在“小对象堆”(SOH)而不是“大对象堆”(LOH)上。

# 数组 每个数组的大小(字节) 分配时间
1,154 532,480 377毫秒
1,319 465,920 412毫秒
1,539 339,360 439 毫秒
1,847 332,800 435毫秒
2,308 266,240 446毫秒
3,077 199,680 491毫秒
4,616 133,120 514毫秒
9,231 66,560 4420毫秒

请注意,在所有情况下,分配的总内存约为586MB,但在最后一种情况下,分配的时间要长一个数量级。

快速解决此性能问题的第一个想法是以某种方式告诉 C# 运行时我想要大型对象堆中的这些数组,即使它们小于阈值。我认为这将使分配时间与其他情况一致。

但是,我似乎无法找到是否有办法做到这一点。看起来以前没有人想要一个对象进入大对象堆。所以,我问:是否有可能以某种方式标记这些数组以强制它们进入大对象堆,即使它们小于 85,000 字节的阈值?

(将 85,000 字节阈值降低到 65,000 字节的方法也可以解决我的问题,但我也找不到解决方法!)

4

1 回答 1

0

阅读https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap后,我假设从第 0 代堆开始的小对象会受到更频繁的垃圾收集. 那些因为仍然被引用而未被收集的可能会被移动以进行压缩。

大型对象堆上的对象有点像第 2 代对象一样处理,并且从一开始就不太频繁地收集。当它们被移动时,其余的不会移动,因为它被认为太贵了。(在阅读您的评论后,您已经保留了对每个数组的引用,小对象的问题可能是为了压缩而移动。)

解决方案:通过保留对小对象的引用来防止垃圾收集,并固定它们以防止在收集其他对象时移动以进行压缩。

(本质上禁用垃圾收集是否可行或可取取决于具体情况。您基本上只能靠自己进行内存管理,并且必须在必要时取消固定(并且,如果到期,取消引用)您的对象以使其可用于收集或压缩,否则您将遇到内存或碎片问题。)

于 2021-11-18T22:20:57.003 回答