全部,
我有以下使用XSLT转换XML文档的代码。 问题是当XML Document大约12MB时,C#内存不足。 是否有不同的方式进行转换而不消耗那么多内存?
public string Transform(XPathDocument myXPathDoc, XslCompiledTransform myXslTrans)
{
try
{
var stm = new MemoryStream();
myXslTrans.Transform(myXPathDoc, null, stm);
var sr = new StreamReader(stm);
return sr.ReadToEnd();
}
catch (Exception e)
{
//Log the Exception
}
}
这是堆栈跟踪:
at System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
at System.Text.StringBuilder.GetNewString(String currentString, Int32 requiredLength)
at System.Text.StringBuilder.Append(Char[] value, Int32 startIndex, Int32 charCount)
at System.IO.StreamReader.ReadToEnd()
at Transform(XPathDocument myXPathDoc, XslCompiledTransform myXslTrans)
答案 0 :(得分:4)
我要做的第一件事就是找出问题所在。使整个MemoryStream业务无法播放,并将输出流式传输到文件,例如:
using (XmlReader xr = XmlReader.Create(new StreamReader("input.xml")))
using (XmlWriter xw = XmlWriter.Create(new StreamWriter("output.xml")))
{
xslt.Transform(xr, xw);
}
如果你仍然得到一个内存不足的例外(我敢打赌你会折钱),这是一个非常公平的迹象,表明问题不在于输出的大小,而在于变换本身的某些东西,例如一种无限递归的东西:
<xsl:template match="foo">
<bar>
<xsl:apply-templates select="."/>
</bar>
</xsl:template>
答案 1 :(得分:3)
MemoryStream + ReadToEnd意味着此时你需要在内存中有2个副本。您可以使用StringWriter对象作为目标(替换MemStream + Reader)将其优化为1个副本,并在完成后使用writer.ToString()。
但这最多只会让你达到24 MB,但仍然太小。还有别的事情要发生 无法说出什么,也许你的XSLT过于复杂或效率低下。
var writer = new StringWriter();
//var stm = new MemoryStream();
myXslTrans.Transform(myXPathDoc, null, writer);
//var sr = new StreamReader(stm);
//return sr.ReadToEnd();
return writer.ToString();
答案 2 :(得分:2)
你需要
stm.Position = 0
在使用StreamReader读取内容之前将内存流重置为开头。否则,您将尝试阅读流末尾的内容。
答案 3 :(得分:0)
ReadToEnd()函数将整个流加载到内存中。最好使用XmlReader以块的形式传输文档,然后针对较小的片段运行xslt。您可能还想考虑完全使用XmlReader传递文档,而不是使用不太适合流式传输数据的xslt,而不能使用大型文件的可扩展性。
答案 4 :(得分:0)
它可能相关也可能不相关,但您需要确保丢弃流和读取器对象。我还添加了Nick Jones指出的位置= 0。
public string Transform(XPathDocument myXPathDoc, XslCompiledTransform myXslTrans)
{
try
{
using (var stm = new MemoryStream())
{
myXslTrans.Transform(myXPathDoc, null, stm);
stm.Position = 0;
using (var sr = new StreamReader(stm))
{
return sr.ReadToEnd();
}
}
}
catch (Exception e)
{
//Log the Exception
}
}
答案 5 :(得分:0)
确保您没有任何JavaScript,否则会出现已知的内存泄漏。
我的回复有效,可以避免许多错误和内存泄漏。用户投票给我,因为他不明白JavaScript可以作为扩展嵌入到XSLT中。
这是一篇旧文章,解释了如何做到这一点。 http://msdn.microsoft.com/en-us/magazine/cc302079.aspx
当通过扩展将JavaScript嵌入到XSLT文档中时,使用XslTransform类时,Web服务器上托管的.Net类已知存在内存泄漏。 JavaScript用于获取日期等内容并进行更多动态处理。这就是我向那些使用JavaScript扩展的人发出警告的原因。这是内存泄漏的最可能原因。另一个警告是使用较新的XslCompliedTransform类时要小心。使用我的大型XSLT文档,我将处理器分配为XslTransform类的4倍和内存的两倍。