我有一个复杂的算法,它从套接字连接接收数据,转换数据并尽快将其存储在HD上。数据,因为我不希望处理速度慢下来存储通过使用不同的线程。 数据存储算法类似于这种结构。它基本上将XML保存在磁盘上。
Begin Thread
beginthread:
XmlTextWriter xmltextWriter;
Save Xml file 1
xmltextWrite.close();
XmlTextWriter xmltextWriter;
Save Xml file 2
xmltextWrite.close();
goto beginthread:
End Thread
它工作正常但是如果我看一下任务管理器,我会注意到我的程序消耗的内存量随着时间的推移而迅速增加(工作1小时后为500mb)。这可能是合理的,因为线程没有进入的数据那么快,.NET框架为我存储临时内存。但我不明白为什么如果传入的套接字连接将停止,即使几分钟后线程继续工作......任务管理器继续显示500Mb的内存..为什么内存没有被重新启动?! XmlTextWriter对象是一个局部变量,每次都会关闭。
根据要求..这是代码的一部分
beginthread:
if (sleeptime < 1000) sleeptime += 2;
try
{
while (hashBeginConn.Count > 0)
{
sleeptime = 0;
int connToApply = hashBeginConn[0];
if (olddate.ToShortDateString() != ListsockConnections[connToApply].beginDate.ToShortDateString())
{
JoinDataFromTempFile(ListsockConnections[connToApply].beginDate.Date.Subtract(olddate.Date).Days, false, d);
olddate = ListsockConnections[connToApply].beginDate.Date;
}
if (tocreate)
{
// XML Serialization
XmlTextWriter xmltextWriter;
Encoding enc = null;
if (ListsockConnections[connToApply].ENCfromCode) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codepage);
if (ListsockConnections[connToApply].ENCDefault) enc = Encoding.Default;
if (ListsockConnections[connToApply].ENCfromText) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codename);
if (enc == null) { enc = null; }
// xmltextWriter = new XmlTextWriter(folderPath + "\\" + cacheFileName, enc);
xmltextWriter = new XmlTextWriter(DataPath + "\\_temp.xml", enc);
xmltextWriter.Formatting = Formatting.Indented;
// Start document
// xmltextWriter.WriteStartDocument();
xmltextWriter.WriteStartElement("ConnectionList");
xmltextWriter.WriteStartElement("connection");
xmltextWriter.WriteStartElement("ConnectionCounter");
xmltextWriter.WriteValue(ListsockConnections[connToApply].ConnectionCounter.ToString());
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("IDConnection");
xmltextWriter.WriteValue(ListsockConnections[connToApply].IDConnection.ToString());
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("Parsed");
xmltextWriter.WriteValue("false");
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("connType");
xmltextWriter.WriteValue("TCP/IP");
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("beginConn");
xmltextWriter.WriteValue(ListsockConnections[connToApply].beginDate.ToString());
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("remoteAddressFamily");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteAdressFamily);
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("remoteIP");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteIP);
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("localIP");
xmltextWriter.WriteValue(ListsockConnections[connToApply].localIP);
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("remoteport");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteport.ToString());
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("localport");
xmltextWriter.WriteValue(ListsockConnections[connToApply].localport.ToString());
xmltextWriter.WriteEndElement();
xmltextWriter.WriteStartElement("dataEncoding");
if (ListsockConnections[connToApply].codepage != 0 || ListsockConnections[connToApply].codename != "")
{
if (ListsockConnections[0].codepage != 0)
{ xmltextWriter.WriteValue(ListsockConnections[connToApply].codepage.ToString()); }
else
{ xmltextWriter.WriteValue(ListsockConnections[connToApply].codename.ToString()); }
}
else
{ xmltextWriter.WriteValue("NONE"); }
xmltextWriter.WriteEndElement();
xmltextWriter.WriteEndElement();
xmltextWriter.WriteEndElement();
xmltextWriter.Flush();
xmltextWriter.Close();
tocreate = false;
}
else
{
FileInfo fi;
FileStream fstream;
//fi = new FileInfo(folderPath + "\\" + cacheFileName);
fi = new FileInfo(DataPath + "\\_temp.xml");
fstream = fi.OpenWrite();
XmlTextWriter xmltextWriter;
Encoding enc = null;
if (ListsockConnections[connToApply].ENCfromCode) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codepage);
if (ListsockConnections[connToApply].ENCDefault) enc = Encoding.Default;
if (ListsockConnections[connToApply].ENCfromText) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codename);
if (enc == null) { enc = null; }
xmltextWriter = new XmlTextWriter(fstream, enc);
xmltextWriter.Formatting = Formatting.Indented;
fstream.Position = fstream.Length - 17;
xmltextWriter.WriteRaw(" <connection>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <ConnectionCounter>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].ConnectionCounter.ToString());
xmltextWriter.WriteRaw("</ConnectionCounter>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <IDConnection>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].IDConnection.ToString());
xmltextWriter.WriteRaw("</IDConnection>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <Parsed>");
xmltextWriter.WriteValue("false");
xmltextWriter.WriteRaw("</Parsed>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <connType>");
xmltextWriter.WriteValue("TCP/IP");
xmltextWriter.WriteRaw("</connType>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <beginConn>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].beginDate.ToString());
xmltextWriter.WriteRaw("</beginConn>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <remoteAddressFamily>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteAdressFamily);
xmltextWriter.WriteRaw("</remoteAddressFamily>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <remoteIP>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteIP);
xmltextWriter.WriteRaw("</remoteIP>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <localIP>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].localIP);
xmltextWriter.WriteRaw("</localIP>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <remotePort>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteport.ToString());
xmltextWriter.WriteRaw("</remotePort>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <localport>");
xmltextWriter.WriteValue(ListsockConnections[connToApply].localport.ToString());
xmltextWriter.WriteRaw("</localport>" + Environment.NewLine);
xmltextWriter.WriteRaw(" <dataEncoding>");
if (ListsockConnections[connToApply].codepage != 0 || ListsockConnections[connToApply].codename != "")
{
if (ListsockConnections[connToApply].codepage != 0)
{
xmltextWriter.WriteValue(ListsockConnections[connToApply].codepage.ToString());
}
else
{
xmltextWriter.WriteValue(ListsockConnections[connToApply].codename.ToString());
}
}
else
{
xmltextWriter.WriteValue("NONE");
}
xmltextWriter.WriteRaw("</dataEncoding>" + Environment.NewLine);
xmltextWriter.WriteRaw(" </connection>" + Environment.NewLine);
xmltextWriter.WriteRaw("</ConnectionList>");
xmltextWriter.Flush();
xmltextWriter.Close();
fstream.Close();
if (fi.Length >= (maxFileTempSize * 1000000))
{
JoinDataFromTempFile(0, false, enc);
}
}
lock (lockThis)
{
hashBeginConn.RemoveAt(0);
}
}
答案 0 :(得分:8)
许多答案都说你必须打电话给Dispose。虽然这些答案意味着很好,但实际上并没有帮助你。您正在调用Close,而Close和Dispose执行相同的操作。使用“使用”块是一种更好的做法,这样你就可以自动为你调用Dispose,但是你的代码很好。
你问题的真正答案是“别再担心了”。你在错误的层面上考虑这个问题。我假设您正在查看任务管理器中的“工作集”或“私有字节”,但您可能无法理解这些实际意味着什么。大多数人没有。这个答案提供了一个很好的总结:
What is private bytes, virtual bytes, working set?
好的,现在您知道“私有字节”是什么,应该更清楚为什么这不是问题。假设您是CLR垃圾收集器。您代表用户分配了一堆内存,并使用它来存储托管对象。垃圾收集器时不时地运行,压缩内存中的对象,并将以前死亡对象以前使用的内存标记为可用。 但是为什么GC会将所有这些内存块返回给操作系统? GC有证据表明你是那种编写使用那么多内存的程序的人,所以它会保留空白页面因此,当你从现在起两毫秒后再次使用那么多内存时,不必再花费再分配它们的费用。
所以,不要再担心了。一切都很好。使用5亿字节的内存不是问题。如果开始虚拟内存不足,GC可能会开始解除对未使用页面的拒绝。如果没有 - 如果它不受限制地增长,那么就开始担心。
如果您仍然担心,请使用正确的工具完成工作。 “私有字节”很少告诉您程序中内存实际发生的情况。 如果您想知道垃圾收集器中究竟发生了什么,那么您需要使用托管内存分析器。它会告诉您具体情况。
答案 1 :(得分:5)
您应该致电xmltextWriter.Dispose()
。
此外,在垃圾收集器启动之前,内存不会被释放。通常应该允许这种情况自动发生,但您可以使用静态方法GC.Collect()显式调用它。建议不要明确调用gc.collect。让CLR按照自己的时间表来做。
答案 2 :(得分:0)
xmltextWriter
拥有非托管资源,在这种情况下是一个操作系统资源的文件。除非您明确地在其上调用Dispose()
,否则它不会释放这些资源。
最佳做法是将编写器的用法括在using { }
块中,以便即使抛出异常也会自动调用Dispose()
。
Dispose()
(或using
)并不保证内存将在该瞬间被释放,但它确实会阻止您的应用程序将文件打开的时间超过所需的时间。