Man*_*rin 13 c# linq garbage-collection out-of-memory linq-to-xml
基本上我有一个程序,当它开始加载文件列表(as FileInfo
)时,对于列表中的每个文件,它加载一个XML文档(如XDocument
).
然后程序将数据从其中读取到容器类(存储为IEnumerables
),此时XDocument
超出范围.
然后程序将数据从容器类导出到数据库.导出后容器类超出范围,然而,垃圾收集器没有清理容器类,因为它的存储IEnumerable
,似乎导致XDocument
留在内存中(不确定这是否是原因,但任务经理正在显示XDocument
未被释放的记忆.
当程序循环遍历多个文件时,程序最终会抛出一个内存不足的异常.为了减轻这种情况,我最终使用了
System.GC.Collect();
Run Code Online (Sandbox Code Playgroud)
在容器超出范围后强制垃圾收集器运行.这是有效的,但我的问题是:
XDocument
内存?谢谢.
编辑:代码示例:
集装箱类:
public IEnumerable<CustomClassOne> CustomClassOne { get; set; }
public IEnumerable<CustomClassTwo> CustomClassTwo { get; set; }
public IEnumerable<CustomClassThree> CustomClassThree { get; set; }
...
public IEnumerable<CustomClassNine> CustomClassNine { get; set; }
Run Code Online (Sandbox Code Playgroud)自定义类:
public long VariableOne { get; set; }
public int VariableTwo { get; set; }
public DateTime VariableThree { get; set; }
...
Run Code Online (Sandbox Code Playgroud)
无论如何,这确实是基本结构.自定义类通过XML文档中的容器类填充.填充的结构本身使用非常少的内存.
从一个XML文档填充容器类,超出范围,然后加载下一个文档,例如
public static void ExportAll(IEnumerable<FileInfo> files)
{
foreach (FileInfo file in files)
{
ExportFile(file);
//Temporary to clear memory
System.GC.Collect();
}
}
private static void ExportFile(FileInfo file)
{
ContainerClass containerClass = Reader.ReadXMLDocument(file);
ExportContainerClass(containerClass);
//Export simply dumps the data from the container class into a database
//Container Class (and any passed container classes) goes out of scope at end of export
}
public static ContainerClass ReadXMLDocument(FileInfo fileToRead)
{
XDocument document = GetXDocument(fileToRead);
var containerClass = new ContainerClass();
//ForEach customClass in containerClass
//Read all data for customClass from XDocument
return containerClass;
}
Run Code Online (Sandbox Code Playgroud)
忘了提这个位(不确定它是否相关),文件可以压缩为.gz所以我有GetXDocument()
方法加载它
private static XDocument GetXDocument(FileInfo fileToRead)
{
XDocument document;
using (FileStream fileStream = new FileStream(fileToRead.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (String.Equals(fileToRead.Extension, ".gz", StringComparison.OrdinalIgnoreCase))
{
using (GZipStream zipStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
document = XDocument.Load(zipStream);
}
}
else
{
document = XDocument.Load(fileStream);
}
return document;
}
}
Run Code Online (Sandbox Code Playgroud)
希望这是足够的信息.谢谢
编辑:在System.GC.Collect()
不工作100%的时间,有时程序似乎保留XDocument
,任何人有任何想法,这可能是为什么?
public static ContainerClass ReadXMLDocument(FileInfo fileToRead)
{
XDocument document = GetXDocument(fileToRead);
var containerClass = new ContainerClass();
//ForEach customClass in containerClass
//Read all data for customClass from XDocument
containerClass.CustomClassOne = document.Descendants(ElementName)
.DescendantsAndSelf(ElementChildName)
.Select(a => ExtractDetails(a));
return containerClass;
}
private static CustomClassOne ExtractDetails(XElement itemElement)
{
var customClassOne = new CustomClassOne();
customClassOne.VariableOne = Int64.Parse(itemElement.Attribute("id").Value.Substring(4));
customClassOne.VariableTwo = int.Parse(itemElement.Element(osgb + "version").Value);
customClassOne.VariableThree = DateTime.ParseExact(itemElement.Element(osgb + "versionDate").Value,
"yyyy-MM-dd", CultureInfo.InvariantCulture);
return customClassOne;
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,强制手动垃圾收集似乎已经解决了你的问题,但是可以肯定的是,这并不比巧合更好.
你需要做的是停止猜测是什么导致了你的记忆压力问题,而是要确定.
我在类似的情况下使用了JetBrains dotTrace非常好的效果 - 设置断点,触发探查器并浏览所有"实时"对象及其关系的视图.可以轻松找到仍保留哪些对象,以及它们保存的引用.
虽然我自己没有使用它,但许多人也推荐使用RedGate Ants Memory Profiler.
这两种工具都有免费试用,这应该足以解决您当前的问题.虽然,我强烈建议购买其中一个 - dotTrace为我节省了数十小时的内存问题,这是一个非常有价值的投资回报率.
你的代码对我来说并不坏看,我也没有看到任何强迫收集的原因.如果您的自定义类包含对XDocument的XElements的引用,那么GC将不会既不收集它们也不收集文档本身.如果其他东西持有对你的枚举的引用,那么它们也不会被收集.所以我真的很想看到你的自定义类定义以及它是如何填充的.
归档时间: |
|
查看次数: |
5597 次 |
最近记录: |