有没有办法让一段代码完全搁置GC?我在其他类似问题中发现的唯一问题是,GC.TryStartNoGCRegion
但它仅限于您指定的内存量,而内存本身的大小仅限于短暂段的大小。
有没有一种方法可以完全绕开它,并告诉.NET “分配您需要的任何内容,不执行GC周期”或增加段的大小?从我发现的结果来看,在许多核心服务器上最多只能有1GB的存储空间,这比我需要分配的空间要少得多,但我还是不想发生GC(我有多达TB的可用RAM,并且有数千个GC峰值在该部分中,我非常乐意将它们换成RAM使用率的10甚至100倍。
现在有了赏金,我认为如果指定用例会更容易。我正在使用LINQ to XML将非常大的XML文件(目前为1GB,不久将为12GB)加载并解析到内存中的对象中。我不是在寻找替代方案。我正在从数百万个对象中创建数百万个小对象,XElements
并且GC会不间断地收集数据,同时我很乐意将所有RAM用完。我有100 GB的RAM,一旦达到4GB的使用量,GC便会开始不间断收集,这对内存非常友好,但对性能却不友好。我不在乎内存,但在乎性能。我想采取相反的权衡。
虽然我无法在此处发布实际代码,但有些示例代码非常接近最终代码,这可能会对那些要求更多信息的人有所帮助:
var items = XElement.Load("myfile.xml")
.Element("a")
.Elements("b") // There are about 2 to 5 million instances of "b"
.Select(pt => new
{
aa = pt.Element("aa"),
ab = pt.Element("ab"),
ac = pt.Element("ac"),
ad = pt.Element("ad"),
ae = pt.Element("ae")
})
.Select(pt => new
{
aa = new
{
aaa = double.Parse(pt.aa.Attribute("aaa").Value),
aab = double.Parse(pt.aa.Attribute("aab").Value),
aac = double.Parse(pt.aa.Attribute("aac").Value),
aad = double.Parse(pt.aa.Attribute("aad").Value),
aae = double.Parse(pt.aa.Attribute("aae").Value)
},
ab = new
{
aba = double.Parse(pt.aa.Attribute("aba").Value),
abb = double.Parse(pt.aa.Attribute("abb").Value),
abc = double.Parse(pt.aa.Attribute("abc").Value),
abd = double.Parse(pt.aa.Attribute("abd").Value),
abe = double.Parse(pt.aa.Attribute("abe").Value)
},
ac = new
{
aca = double.Parse(pt.aa.Attribute("aca").Value),
acb = double.Parse(pt.aa.Attribute("acb").Value),
acc = double.Parse(pt.aa.Attribute("acc").Value),
acd = double.Parse(pt.aa.Attribute("acd").Value),
ace = double.Parse(pt.aa.Attribute("ace").Value),
acf = double.Parse(pt.aa.Attribute("acf").Value),
acg = double.Parse(pt.aa.Attribute("acg").Value),
ach = double.Parse(pt.aa.Attribute("ach").Value)
},
ad1 = int.Parse(pt.ad.Attribute("ad1").Value),
ad2 = int.Parse(pt.ad.Attribute("ad2").Value),
ae = new double[]
{
double.Parse(pt.ae.Attribute("ae1").Value),
double.Parse(pt.ae.Attribute("ae2").Value),
double.Parse(pt.ae.Attribute("ae3").Value),
double.Parse(pt.ae.Attribute("ae4").Value),
double.Parse(pt.ae.Attribute("ae5").Value),
double.Parse(pt.ae.Attribute("ae6").Value),
double.Parse(pt.ae.Attribute("ae7").Value),
double.Parse(pt.ae.Attribute("ae8").Value),
double.Parse(pt.ae.Attribute("ae9").Value),
double.Parse(pt.ae.Attribute("ae10").Value),
double.Parse(pt.ae.Attribute("ae11").Value),
double.Parse(pt.ae.Attribute("ae12").Value),
double.Parse(pt.ae.Attribute("ae13").Value),
double.Parse(pt.ae.Attribute("ae14").Value),
double.Parse(pt.ae.Attribute("ae15").Value),
double.Parse(pt.ae.Attribute("ae16").Value),
double.Parse(pt.ae.Attribute("ae17").Value),
double.Parse(pt.ae.Attribute("ae18").Value),
double.Parse(pt.ae.Attribute("ae19").Value)
}
})
.ToArray();
目前,我能找到的最好的方法是切换到具有较大段大小的服务器GC(本身没有做任何更改),并且让我在没有gc部分的情况下使用更大的数字:
GC.TryStartNoGCRegion(10000000000); // On Workstation GC this crashed with a much lower number, on server GC this works
这违背了我的期望(这是10GB,但是从在线文档中我可以找到,我当前设置中的段大小应该是1到4GB,所以我期望使用无效的参数)。
通过此设置,我可以得到想要的结果(GC处于保留状态,我分配了22GB而不是7GB的空间,所有临时对象均未进行GC处理,但是GC在整个批处理过程中仅运行了一次(一次!),而不是很多每秒多次(在更改Visual Studio中的GC视图之前,从GC触发的所有单个点看都是一条直线)。
这不是很好,因为它无法扩展(添加0会导致崩溃),但是它比我到目前为止发现的任何其他东西都要好。
除非有人发现如何增加段大小,以便我可以进一步扩大它,或者有更好的选择来完全停止GC(不仅是特定的一代,而且要全部停止),否则几天后我会接受我自己的答案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句