Can anybody explain the following?
Say I have the following source XML and XSLT (see below). No matter what
this XSLT does. It is just a sample to show a problem. the idea is that
XSLT transforms small XML into quite big XML. Now, I have a straightforward
C# (see below) code that does this transform and writes result into XmlTextWriter.
(Oleg's NXSLT.EXE is also suitable).
Problem:
If source XML is bigger, say several MBs (please don't explain me that it
is not good to use XSLT for such documents), the sample transform should
produce a very big (add more calls to template b if necessary and <a /> elements
to source document) XML. While result is writtent to the writer I expect
that it will not consume much more memory that source document. (I even
tried to provide custom XmlWriter which runs GC each 1000 element outputed).
However, I get OutOfMemory exception.
So, I looked at heap and what I see. I have in memory one 0.5GB object.
It is System.String containing:
uri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaau ri:aaauri:aaauri:aaauri:aaauri:aaa................ ...(much
longer - 0.5 GB)
Samples below generate smaller string, but anyway it is many times concantenated
namespaces declared in XSLT (except XSLT namespace).
This XSLT runs fine in MSXML4 producing output to SAXHandler interface.
Any ideas how to avoid this long string in memory?
Parts of memory dump:
=== DUMP ===
..load sos
!DumpHeap -type System.String
PDB symbol for mscorwks.dll not loaded
succeeded
Loaded Son of Strike data table version 5 from "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\msco rwks.dll"
Address MT Size
00af117c 79c125c8 28
00af11f0 79c125c8 108
00af125c 79c125c8 20
...........
>>>>> I WILL DUMP THIS >>>>>00b3bf04 79c125c8 104400b3d524 79c125c8 76
00b3d570 79c125c8 76
00b3d5bc 79c125c8 84
total 1647 objects
Statistics:
MT Count TotalSize Class Name
79c125c8 1647 91732 System.String
Total 1647 objects
!DumpObj 00b3bf04
Name: System.String
MethodTable 0x79c125c8
EEClass 0x79c12914
Size 1044(0x414) bytes
mdToken: 0200000f (c:\windows\microsoft.net\framework\v1.1.4322\msco rlib.dll)
String: uri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaau ri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaaur i:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri :aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri: aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:aaauri:a aauri:aaauri:aaauri:aaauri:aaauri:aaa
FieldDesc*: 79c12978
MT Field Offset Type Attr Value Name
79c125c8 4000013 4 System.Int32 instance 513 m_arrayLength
79c125c8 4000014 8 System.Int32 instance 287 m_stringLength
79c125c8 4000015 c System.Char instance 75 m_firstChar
79c125c8 4000016 0 CLASS shared static Empty Domain:Value 00148f98:00af125c << 79c125c8 4000017 4 CLASS shared static WhitespaceChars Domain:Value 00148f98:00af1270 <<
======== XML ========
<xml>
<a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a />
<a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a />
<a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a />
<a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a /> <a />
</xml>
======== XSLT ========
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="uri:aaa"
version="1.0"
<xsl:output method="xml" encoding="utf-8" />
<xsl:template name="b">
<c />
</xsl:template>
<xsl:template match="a">
<xsl:call-template name="b" />
<xsl:call-template name="b" />
<xsl:call-template name="b" />
<xsl:call-template name="b" />
</xsl:template>
<xsl:template match="/xml">
<xml>
<xsl:apply-templates />
</xml>
</xsl:template>
</xsl:transform>
====== C# ===============
namespace some {
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
class App {
[STAThread] static void Main(string[] args) {
XslTransform transform = new XslTransform();
transform.Load(args[1]);
XPathDocument source = new XPathDocument(args[0]);
XmlTextWriter writer = new XmlTextWriter(args[2], Encoding.UTF8);
XsltArgumentList xslArgs = new XsltArgumentList();
transform.Transform(source, xslArgs, writer);
writer.Close();
}
}
}