有没有办法完全搁置一段代码的GC?我在其他类似问题中发现的唯一问题是GC.TryStartNoGCRegion
,但它受您指定的内存容量的限制,而内存容量本身又受短暂段的大小限制。
有没有办法完全绕过这一点,告诉.NET“分配你需要的任何东西,不要做GC周期”或者增加段的大小?从我发现在多核服务器上最多是1 1GB,这远远少于我需要分配的容量,但我不希望GC发生(我有高达to的空闲RAM,在此期间有数千个GC峰值,我非常乐意用这些内存换取RAM使用量的10倍甚至100倍)。
编辑:
既然有了赏金,我想如果我指定用例就更容易了。我正在使用LINQ to XML加载和解析一个非常大的XML文件(现在是1 1GB,很快是12 1GB)到内存中的对象。我并不是在寻找替代方案。我正在从数以百万计的XElements
中创建数以百万计的小对象,而GC正在尝试不间断地收集数据,同时我也非常乐意让所有的内存都用完。我有100 4GB的RAM,一旦达到4 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();
发布于 2016-05-23 11:22:42
目前我能找到的最好的方法是切换到服务器GC (它本身没有改变任何东西),它有更大的段大小,并且让我使用一个更大的数字来表示没有gc部分:
GC.TryStartNoGCRegion(10000000000); // On Workstation GC this crashed with a much lower number, on server GC this works
这与我的预期不符(这是10 4GB,但从我在联机文档中可以找到的信息来看,我当前设置中的段大小应该是1到4 4GB,所以我期望得到一个无效的参数)。
通过这种设置,我得到了我想要的(GC处于等待状态,分配了22 GC而不是7 GC,所有的临时对象都不是GCed,但是GC只运行一次(一次!)整个批处理过程,而不是每秒很多很多次(在更改之前,visual studio中的GC视图看起来就像一条直线,来自GC触发的所有单独的点)。
这不是很好,因为它不会扩展(添加0导致崩溃),但它比我到目前为止发现的任何其他东西都要好。
除非有人发现如何增加段的大小,以便我可以进一步推进,或者有更好的替代方案来完全停止GC (不只是某一代,而是所有的GC),否则我将在几天内接受我自己的答案。
发布于 2016-05-19 21:57:52
我认为在您的情况下最好的解决方案是我以前在我的一个项目中使用的这段代码
var currentLatencySettings = GCSettings.LatencyMode;
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
//your operations
GCSettings.LatencyMode = currentLatencySettings;
您正在尽可能地抑制(据我所知),并且您仍然可以手动调用GC.Collect()
。
请查看MSDN文章here
此外,我强烈建议使用LINQ Skip()
和Take()
方法对已解析的集合进行分页。最后连接输出数组
发布于 2016-05-23 13:06:09
我不确定在您的情况下是否可能,但是您是否尝试过并行处理XML文件。如果您可以将XML文件分解为较小的部分,则可以从代码中派生多个进程。每个进程处理一个单独的文件。然后,您可以合并所有结果。这肯定会提高您的性能,而且对于每个单独的进程,您将有其单独的内存分配,这也应该在处理所有XML文件时增加特定时间的内存分配。
https://stackoverflow.com/questions/37262774
复制相似问题