使用XmlDocument()时发生内存泄漏

3
我认为我在使用XmlDocument类的某些代码中存在内存泄漏。
我的程序在运行于Windows 6.1.4设备(C#)上,从另一服务器的数据库读取信息,以查看是否需要卸载设备上安装的任何程序,然后从XmlDocument中读取可卸载程序的名称列表。如果需要,程序会进行匹配并进行卸载。这个过程被无限循环,并在后台运行,但我注意到随着时间的推移,内存缓慢地增加,最终程序会抛出OutOfMemoryException异常。
如果我注释掉所有内容并在循环中不执行任何操作,则内存保持在2MB左右。如果我只注释掉以下代码,则内存使用量每分钟增加0.05兆字节左右,且连续增加。这些结果是在让循环休眠1秒钟的情况下获得的。正常的休眠速度大约为10分钟。有什么想法可以解决这个内存泄漏问题,如果它与XmlDocument类有关?
foreach (string programName in uninstallPrograms)
{
    XmlDocument xmlDoc1 = new XmlDocument();
    xmlDoc1.LoadXml("<wap-provisioningdoc>" +
          "  <characteristic type=\"UnInstall\">" +
          "    <characteristic type=\"" + programName + "\">" +
          "     <parm name=\"uninstall\" value=\"1\"/>" +
          "    </characteristic>" +
          "  </characteristic>" +
          "</wap-provisioningdoc>");

    xmlDoc1 = ConfigurationManager.ProcessConfiguration(xmlDoc1, true);

    cmdStr += "DELETE FROM DEVICE_APPS WHERE ID = " + deviceAppIDList[count++] + "; ";

    xmlDoc1 = null;
}

// Check for pre-installed apps to uninstall
count = 0;

XmlDocument xmlDoc2 = new XmlDocument();

xmlDoc2.LoadXml("<wap-provisioningdoc><characteristic-query type=\"UnInstall\"/>" +
        "</wap-provisioningdoc>");

/**** The line below seems to be the cause of the memory leak ****/
//xmlDoc2 = ConfigurationManager.ProcessConfiguration(xmlDoc2, true);

XmlNodeList xmlNodeList = xmlDoc2.SelectNodes("wap-provisioningdoc/" +
        "characteristic[@type='UnInstall']/characteristic/@type");

xmlDoc2 = null;

cmdStr 最终会被使用并在循环结束时设置为 string.Empty。起初我没有在代码中加入 xmlDoc = null;,但无论如何都没有帮助。我尝试在循环末尾添加 GC.Collect();,这似乎有助于减缓泄漏,但它不能完全解决问题。此外,我读过使用它不是好的实践方法。

编辑:所以似乎是我在上面代码中注释掉的 ConfigurationManager 行具有内存泄漏。一旦我注释掉那行代码,内存泄漏就停止了。当我取消注释时,它又开始了。在调用 ProcessConfiguration 后,我需要做些什么才能释放内存吗?

另外,我正在使用 Microsoft.WindowsMobile.Configuration 命名空间的 ConfigurationManager 运行时版本 1.1.4322,因为 CF 中不存在 System.Configuration。


4
顺便说一下,一旦有人添加一个非平凡的程序名称,你的代码就会出问题;将字符串串联成XML时,如果不对其进行编码,则存在危险 - 可能会导致损坏的XML。 - Marc Gravell
请注意,我已编辑了您问题中的代码部分。你只需要在代码前加上四个空格即可,不需要使用precode HTML标签。 - user47589
这是正确的,Marc,但是填充programName的数据是从数据库中检索出来的,而数据库是由手持设备填充的。所以,如果数据库变得损坏,肯定会有问题,但更大的问题是什么。感谢Inuyasha的修复! - Zac
5个回答

2

当我遍历许多 ~100 MB 的 XML 文件时,遇到了类似的问题。我尝试了上面提到的所有方法,但都没有帮助。最后,我将 XML 处理分离成一个单独的虚拟函数,然后垃圾回收正常工作了。我做了这样的事情:

function f()
{
    FileInfo[] rgFiles = di.GetFiles("*.xml.gz", SearchOption.TopDirectoryOnly);
    //process all *.xml.gz files in folder
    foreach (FileInfo fi in rgFiles)
    {
        forGC(fi);
    }
}

函数forGC完成了所有工作。现在垃圾回收知道何时可以从内存中删除XML。


0

你可以将cmdStr的类型更改为StringBuilder。 因为字符串是不可变的,每次向字符串附加内容时都会复制它。


0

看起来解决这个问题的方法是使用本地的DMProcessConfigXML()。使用这种方法不会导致内存泄漏。因此,包装器中必须有一些未正确释放其资源的东西。


0
在你的代码中,cmdStr会越来越大,但我没有看到它被使用...这会导致内存消耗无限增长,并导致OutOfMemory异常...

抱歉,我应该提到那个变量稍后会被使用,并在循环结束时通过 cmdStr = string.Empty 进行重置。我没有放置循环内所有的代码,因为其中有很多代码。但我已将其缩小到这一块。 - Zac
Global.WriteToFile 是做什么的?你能否将这些调用注释掉并重新检查,或者展示一下这个方法的源代码? - Yahia
内存增长仍然相同。 - Zac
好的...那么缩小范围尝试的唯一剩下的事情就是注释掉对ConfigurationManager的调用...然后再次检查... - Yahia
有趣...看起来是与ConfigurationManager相关的代码行。一旦我注释掉那行代码,内存就稳定了,泄漏也停止了。 - Zac
显示剩余2条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接