I have some C# code that reads a huge file, and after some manipulation, sets its reference to null and exits the function, but the memory won't free up.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
XmlService.ConvertExcelToXML(xmlDoc);
int sdfid = 320;
XmlService.CompareXML(xmlDoc, ref sdfid, pkid);
xmlDoc.RemoveAll();
xmlDoc = null;
The xmlDoc
is a very big string, usually around 50 MB. When I exit the function, that memory is permamnently occupied, and I have to restart my service couple of times a day, otherwise it's memory usage reaches 1GB.
I have tried to use GC.Collect, but no use.
Thank you in advance.
Edit
Here is the class declaration for XmlService. It has no variables. All methods are static
public class XmlService
ConvertExcelToXML function's code
public static bool ConvertExcelToXML(XmlDocument xmlDoc) {
XmlNamespaceManager nm = new XmlNamespaceManager(xmlDoc.NameTable);
nm.AddNamespace("z", "urn:schemas-microsoft-com:office:spreadsheet");
nm.AddNamespace("o", "urn:schemas-microsoft-com:office:office");
nm.AddNamespace("x", "urn:schemas-microsoft-com:office:excel");
nm.AddNamespace("ss", "urn:schemas-microsoft-com:office:spreadsheet");
nm.AddNamespace("html", "http://www.w3.org/TR/REC-html40");
XmlNodeList rows = xmlDoc.DocumentElement.SelectNodes("//z:Worksheet/z:Table/z:Row", nm);
if (rows != null && rows.Count > 0)
{
XmlNode nodeNames = rows[0];
XmlNode nodeValues = rows[1];
XmlNode destRootNode = xmlDoc.CreateNode(XmlNodeType.Element, "ParentNode", null);
XmlNode fieldNode = null;
XmlNode dataNode = null;
for (int i = 0; i < nodeNames.ChildNodes.Count; i++)
{
if (nodeNames.ChildNodes[i].HasChildNodes)
{
string nodeName = nodeNames.ChildNodes[i].ChildNodes[0].InnerXml;
//string nodeValue = nodeValues.ChildNodes[i].ChildNodes[0].InnerXml;
string nodeValue = "DataField" + i.ToString();
fieldNode = xmlDoc.CreateNode(XmlNodeType.Element, "Field", null);
dataNode = xmlDoc.CreateNode(XmlNodeType.Element, "Data", null);
dataNode.InnerXml = nodeName;
fieldNode.AppendChild(dataNode);
destRootNode.AppendChild(fieldNode);
fieldNode = xmlDoc.CreateNode(XmlNodeType.Element, "Field", null);
dataNode = xmlDoc.CreateNode(XmlNodeType.Element, "Data", null);
dataNode.InnerXml = nodeValue;
fieldNode.AppendChild(dataNode);
destRootNode.AppendChild(fieldNode);
}
}
xmlDoc.LoadXml("<ParentNode>" + destRootNode.InnerXml + "</ParentNode>");
return true;
}
return false;
}
and Code for CompareXML
public static void CompareXML(XmlDocument filexmlDoc, ref int maxSDFID, string PKID)
{
FieldsListBO tmpFieldListBO = null;
ResponseDTO responseDTO = DbService.getConnection();
DbConnection con = (DbConnection)responseDTO.ReturnedObjects[Constants.CONNECTION_OBJECT];
DbProviderFactory factory = (DbProviderFactory)responseDTO.ReturnedObjects[Constants.FACTORY_OBJECT];
Db开发者_运维百科Command cmd = factory.CreateCommand();
cmd.CommandText = "select * from tree_store";
cmd.Connection = con;
con.Open();
DbDataReader dr = cmd.ExecuteReader();
dr.Read();
String pXmlizedString = (String)dr["TransactionTree"];
dr.Dispose();
cmd.Dispose();
con.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(FieldsListBO));
MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII);
tmpFieldListBO = (FieldsListBO)xs.Deserialize(memoryStream);
memoryStream.Dispose();
xmlTextWriter.Close();
if (tmpFieldListBO.FieldsList.Count < 1)
{
maxSDFID = 0;
return;
}
FieldsListBO fieldListBO = new FieldsListBO();
for (int i = 0; i < tmpFieldListBO.FieldsList.Count; i++)
{
if (tmpFieldListBO.FieldsList[i]._pkid.Equals(PKID))
{
fieldListBO.FieldsList.Add(tmpFieldListBO.FieldsList[i]);
}
}
GetMaxSDFID(filexmlDoc, ref maxSDFID, fieldListBO);
}
filexmlDoc being passed to GetMaxSDFID is just being transversed node by node no update/delation is done
I'm sorry to say this, and I could be wrong, but it really looks like you're guessing at the source of the problem.
I say this is because of what you tried to do. Nulling out a local variable and calling GC.Collect in the hopes that this will fix it. Experienced people will tell you this isn't it and won't help.
Guessing is often a good approach (for instance others have guessed XmlService.ConvertExcelToXML
might be a problem), but why guess when you don't have to, get a memory dump of the process when your application has consumed a significant amount of memory. You can use ProcDump but there are many other ways to do this.
Install WinDbg. With this tool you can analyze your memory dump with commands like !dumpheap –stat
that can tell you exactly where the 1 GB is going.
We'd need to know what XmlService
does in order to have more of a clue of what's going on. It could easily be storing the data for some reason (or possibly for no reason other than poor design).
Assuming the method ends shortly after the code you've shown us, you definitely shouldn't need to set the variable to null, and if XmlService
isn't holding a reference to the object, you shouldn't need to call RemoveAll
either.
Note that the XmlDocument
object itself won't be very large, although its object graph may be. xmlString
itself may be large though - if you end up with a lot of objects on the large object heap, that may be causing problems for you, as the LOH isn't compacted even after the space is freed. I wouldn't have expected it to behave quite like this though.
Do you have to get the XML into a string variable to start with? Could you stream it (e.g. from a file) instead?
精彩评论