大阵列和LOH碎片.什么是公认的惯例?

Gor*_*r H 12 c# arrays large-object-heap

我有一个其他有效的问题这里关于这可能涉及LOH碎片可能还有其他未知因素中的一些绝望的内存问题.

我现在的问题是,接受的做事方式是什么?如果我的应用程序需要在Visual C#来完成,并且需要处理大型阵列的INT [4000000]调,我怎么能被垃圾收集器拒绝处理LOH注定?

似乎我被迫将任何大型数组全局化,并且从不在它们周围使用"new"这个词.所以,我留下了带有"maxindex"变量的不合适的全局数组,而不是由函数传递的整齐大小的数组.

我总是被告知这是不好的做法.还有什么选择?

是否有某种功能System.GC.CollectLOH("Seriously")?是否有可能将垃圾收集外包给System.GC以外的其他方式?

无论如何,处理大型(> 85Kb)变量的普遍接受的规则是什么?

Pau*_*ane 26

首先,垃圾收集器确实收集了LOH,因此不要立即被它的早期吓到.收集第2代时收集LOH.

不同之处在于LOH不会被压缩,这意味着如果你的物体有一个很长的使用寿命,那么你将有效地将LOH分成两个部分 - 前面的区域和该物体之后的区域.如果这种情况继续发生,那么你可能会遇到长期对象之间的空间不足以进行后续分配的情况,并且.NET必须分配越来越多的内存以放置大对象,即LOH变得支离破碎.

现在,话虽如此,如果LOH的末端区域完全没有活物,那么LOH的大小会缩小,所以唯一的问题是如果你将物体留在那里很长时间(例如应用的持续时间).

避免LOH碎片的策略是:

  • 避免创建悬挂的大型对象.基本上这只是意味着大型数组或包装大型数组的对象(例如包装字节数组的MemoryStream),因为没有其他东西那么大(复杂对象的组件分别存储在堆上,所以很少很大).还要注意大词典和列表,因为它们在内部使用数组.
  • 注意双阵列 - 这些进入LOH的门槛要小得多,要小得多 - 我不记得确切的数字,但只有几千.
  • 如果你需要一个MemoryStream,考虑制作一个支持许多较小阵列而不是一个大阵列的分块版本.您还可以使用分块来制作IList和IDictionary的自定义版本,以避免首先出现在LOH中的内容.
  • 避免很长的Remoting调用,因为Remoting大量使用MemoryStreams,它可以在调用期间分割LOH.
  • 注意字符串实习 - 由于某些原因,它们作为页面存储在LOH上,如果你的应用程序继续遇到新的字符串到实习生,可能会造成严重的碎片,即避免使用string.Intern,除非已知字符串集是有限的在应用程序的生命早期遇到全套.(见我之前的问题.)
  • 使用罢工之子来查看使用LOH内存究竟是什么.再次看到这个问题有关如何执行此操作的详细信息.

编辑:双阵列的LOH阈值似乎是8k.

  • 此外,您可以显然从Visual Studio中的立即窗口加载SOS(避免需要CDB),但我从未尝试过. (2认同)

bwi*_*ing 8

这是一个老问题,但我认为用.NET中引入的更改更新答案并没有什么坏处.现在可以对大对象堆进行碎片整理.显然,首选应该是确保做出最好的设计选择,但现在有这个选择是很好的.

https://msdn.microsoft.com/en-us/library/xe0c2357(v=vs.110).aspx

"从.NET Framework 4.5.1开始,您可以通过在调用Collect方法之前将GCSettings.LargeObjectHeapCompactionMode属性设置为GCLargeObjectHeapCompactionMode.CompactOnce来压缩大对象堆(LOH),如以下示例所示."

可以在System.Runtime命名空间中找到GCSettings

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(); 
Run Code Online (Sandbox Code Playgroud)


kem*_*002 7

我想到的第一件事就是将阵列分成较小的阵列,这样它们就无法到达GC所需的内存来放入LOH.你可以将数组吐成10,000个较小的数组,然后构建一个对象,根据你传递的索引器知道要查找哪个数组.

现在我还没有看到代码,但我也会质疑为什么你需要一个大的数组.我可能会考虑重构代码,因此所有这些信息不需要立即存储在内存中.


小智 6

你弄错了.你不需要有4000000的数组大小,你绝对不需要调用garbace收集器.

  • 编写自己的IList实现.喜欢"PagedList"
  • 将项目存储在65536个元素的数组中.
  • 创建一个数组数组来保存页面.

这允许您仅使用一个重定向访问基本上所有元素.并且,由于单个阵列较小,碎片不是问题...

......如果是......那么REUSE页面.不要把它们扔掉处理掉,把它们放在一个静态的"PageList"上并先从那里拉出来.所有这些都可以在你的课堂上透明地完成.

真正的好处是这个List在内存使用方面非常动态.您可能想要调整holder数组(重定向器)的大小.即使没有,也只是每页约512kbdata.

第二级数组基本上每字节64k - 一个类为8字节(每页512kb,32位256kb),或每个结构字节64kb.

技术上:

将int []转换为int [] []

根据需要确定32位或64位是否更好;)两者都有优点和缺点.

处理一个像这样的大型阵列在任何语言中都是不可思议的 - 如果你愿意,那么......基本上....在程序启动时分配,永远不会重新创建.只有解决方案