gpt4 book ai didi

c# - XDocument + IEnumerable 导致 System.Xml.Linq.dll 内存不足异常

转载 作者:可可西里 更新时间:2023-11-01 08:05:59 31 4
gpt4 key购买 nike

基本上我有一个程序,当它开始时加载一个文件列表(如 FileInfo),并为列表中的每个文件加载一个 XML 文档(如 XDocument).

程序然后从其中读取数据到容器类(存储为 IEnumerables),此时 XDocument 超出范围。

程序然后将数据从容器类导出到数据库。然而,在导出容器类超出范围后,垃圾收集器并未清理容器类,因为它存储为 IEnumerable,似乎导致了 XDocument 留在内存中(不确定这是否是原因,但任务管理器显示 XDocument 中的内存未被释放)。

由于程序循环遍历多个文件,最终程序抛出内存不足异常。为了缓解这种情况,我最终使用了

System.GC.Collect(); 

强制垃圾收集器在容器超出范围后运行。这是可行的,但我的问题是:

  • 这样做正确吗? (强制垃圾收集器运行似乎有点奇怪)
  • 是否有更好的方法来确保释放 XDocument 内存?
  • 除了 IEnumerable 之外,是否还有其他原因导致文档内存未被释放?

谢谢。


编辑:代码示例:

  • 容器类:

    public IEnumerable<CustomClassOne> CustomClassOne { get; set; }
    public IEnumerable<CustomClassTwo> CustomClassTwo { get; set; }
    public IEnumerable<CustomClassThree> CustomClassThree { get; set; }
    ...
    public IEnumerable<CustomClassNine> CustomClassNine { get; set; }
  • 自定义类:

    public long VariableOne { get; set; }
    public int VariableTwo { get; set; }
    public DateTime VariableThree { get; set; }
    ...

    无论如何,这确实是基本结构。自定义类通过 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;
}

忘记提到这一点(不确定它是否相关),文件可以压缩为 .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;
}
}

希望这是足够的信息。谢谢

编辑 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;
}

最佳答案

在某些情况下,强制手动垃圾收集似乎已经解决了您的问题,但可以肯定的是,这只不过是巧合。

您需要做的是停止猜测是什么导致了您的内存压力问题,而是要确定地找出答案。

我用过 JetBrains dotTrace在类似情况下效果非常好 - 设置断点,触发探查器并浏览所有“实时”对象及其关系的 View 。可以很容易地找到哪些对象仍然保留,以及它们通过哪些引用保持事件状态。

虽然我自己没有使用过,但 RedGate Ants Memory Profiler也是很多人推荐的。

这两款工具都有免费试用,应该足以解决你目前的问题。不过,我强烈建议两者都值得购买 - dotTrace 为我节省了数十小时的内存问题排查时间,这是非常值得的投资返回率。

关于c# - XDocument + IEnumerable 导致 System.Xml.Linq.dll 内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4452581/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com