我还有一个活跃的问题,关于一些毫无希望的记忆问题,可能涉及到loh碎片和其他未知因素。
我现在的问题是,什么是公认的做事方式?
如果我的应用程序需要在Visual C中完成,并且需要处理大数组到INT(4000000)的曲调,那么垃圾收集器拒绝处理LOH怎么办?
似乎我被迫将任何大型数组设为全局数组,并且从未在其中任何一个数组周围使用“new”一词。所以,剩下的是带有“maxIndex”变量的不规则全局数组,而不是由函数传递的大小整齐的数组。
我一直被告知这是一个糟糕的做法。还有别的选择吗?
有什么功能可以调节System.GC.CollectLOH("Seriously")
是否有可能将垃圾收集外包给system.gc以外的其他对象?
不管怎样,处理大型(>85kb)变量的一般公认规则是什么?

最佳答案

首先,垃圾收集者确实收集了loh,所以不要被它的先见之明吓到。当第2代被收集时,loh被收集。
不同的是loh没有被压缩,这意味着如果你有一个对象在那里有很长的生命周期,那么你将有效地把loh分成两个部分-在此对象之前的区域和之后的区域。如果这种行为继续发生,那么您可能会出现这样的情况:长寿命对象之间的空间不够大,无法进行后续分配,.net必须分配越来越多的内存来放置您的大型对象,即loh变得碎片化。
现在,尽管如此,如果loh末端的区域完全没有活动对象,那么loh的大小可能会缩小,因此唯一的问题是如果您将对象放在其中很长时间(例如,应用程序的持续时间)。
从.net 4.5.1开始,loh可以被压缩,参见GCSettings.LargeObjectHeapCompactionMode属性。
避免loh片段化的策略有:
避免创建挂在周围的大型对象。基本上,这只是意味着大数组,或者包装大数组的对象(比如包装字节数组的memoryStream),因为没有其他东西那么大(复杂对象的组件单独存储在堆中,所以很少很大)。还要注意大型字典和列表,因为它们在内部使用数组。
注意双数组-这些进入loh的阈值要小得多-我记不清确切的数字,但只有几千个。
如果您需要一个memoryStream,可以考虑制作一个分块版本,它将返回到多个较小的数组,而不是一个巨大的数组。您还可以制作IList和IDictionary的自定义版本,它们首先使用分块来避免内容在LOH中结束。
避免非常长的远程处理调用,因为远程处理大量使用memorystreams,这些memorystreams可以在调用的长度内分段loh。
注意字符串实习-由于某些原因,这些存储为loh上的页面,如果应用程序继续遇到要实习的新字符串,可能会导致严重的碎片,也就是说,避免使用string.intern,除非已知字符串集是有限的,并且在应用程序生命早期遇到了完整的字符串集。(见my earlier question
用斯泰克之子看看到底是什么在使用loh记忆。有关如何执行此操作的详细信息,请再次参见this question
考虑pooling large arrays
编辑:双数组的loh阈值似乎为8k。

08-04 12:02