2010-05-17 15 views
9

Ich schreibe ein Programm für die Formatierung von 100 MB-String-Daten (in der Nähe eines Gig) in xml == Und ich bin es erforderlich, um es als Antwort auf eine HTTP (GET) Anfrage zurückzugeben.Sehr große Zeichenfolge im Speicher

Ich bin mit einem Stringwriter/XmlWriter eine XML der Datensätze in einer Schleife zu bauen und die

using (StringWriter writer = new StringWriter()) 
using (writer = XmlWriter.Create(writer, settings)) //where settings are the xml props 

writer.ToString() 

während des Testens der Rückkehr sah ich ein paar --out Speicher exceptions-- und ganz ahnungslos, wie eine Lösung finden? Habt ihr Vorschläge für eine speicheroptimierte Antwort?

Gibt es eine speichereffiziente Möglichkeit, die Daten zu codieren? oder vielleicht die Daten Chunking - Ich kann einfach nicht daran denken, wie es zurückzukehren, ohne das Ganze zu einer riesigen String-Objekt zu bauen

dank

- einige Präzisierungen - dies ist ein asp .net Webservices App über eine Gigabit-Ethernet-Verbindung als Josh notiert. Ich bin damit nicht sehr vertraut, also noch ein bisschen eine Lernkurve.

ich XMLWriter bin mit dem XML zu erstellen und eine Zeichenfolge aus ihm heraus erstellen String mit

einige Statistiken - Antwort xml size = etwa 385 MB (meine Daten Größe sehr schnell wachsen wird auf weit mehr als diese)

String Objektgröße, wie durch einen Speicher-Profiler berechnet = kulminierte an 605MB

und vielen dank an alle, die geantwortet haben ...

+9

1 GB xml als HTTP-Antwort? "Ja wirklich?" –

+1

Das klingt nach einer schlechten Idee. –

+0

Ich bin versucht zu sagen "werfen Sie ein paar Hardware" (Scherz). 500 MB (oder 350 MB oder 1 GB) pro Client sind nicht skalierbar. Vielleicht könnten Sie etwas mehr Licht auf XML werfen, das Sie generieren. Diese http://msdn.microsoft.com/en-us/library/aa528818.aspx könnte helfen. – PRR

Antwort

4

Können Sie nicht einfach die Antwort auf den Client streamen? XmlWriter erfordert nicht, dass der zugrunde liegende Stream im Arbeitsspeicher gepuffert wird. Wenn es ASP.NET ist, können Sie den Response.OutputStream verwenden, oder wenn es WCF ist, können Sie response streaming verwenden.

+0

Josh, dies ist ein Web-Service-Projekt - Client-Anfragen über GET auf die Web-Methode - neu zu Microsoft-Lösungen, ich bin nicht sicher, ob es möglich ist und wie – bushman

+0

Es ist wahrscheinlich nicht möglich mit ASMX Web-Services und wenn das was ist Ich würde sehr empfehlen, auf WCF zu wechseln, bevor es zu schwierig ist, es neu zu gestalten. Sie sind bereits auf eine der Einschränkungen von ASMX gestoßen und es gibt viele andere, die nicht nur auf die Leistung beschränkt sind. Mit WCF können Sie jedoch ein Stream-Objekt zurückgeben und die Daten an den Aufrufer chunkieren. Es ist alles eingebaut. – Josh

+0

danke josh !. Tolle Eingaben von allen aber werden dies als die passende Antwort markieren. – bushman

0

Sie werden jeden Datensatz zurückkehren (oder eine kleine Gruppe von rec ords) auf ihren eigenen individuellen GETs.

5

Verwenden Sie XmlTextWriter gewickelt um Reponse.OutputStream, um die XML an den Client zu senden und die Antwort regelmäßig zu leeren. Auf diese Weise müssen Sie nie mehr als ein paar MB im Speicher haben (zumindest für das Senden an den Client).

+0

Es klingt wie er das XML mit String-Manipulation zusammenbaut. – SLaks

+1

@SLaks, Klingt, als könnte er alles tun, weil er es wirklich nicht gesagt hat. –

+0

+1. Oder wickle den "XmlTextWriter" um einen 'GZipStream' herum, der um' Response.OutputStream' gewickelt ist. – Steven

1

HTTP erhalten für 1 Gig? das ist eine Menge! Vielleicht solltest du es noch einmal überdenken. Zumindest gziping der Ausgang könnte helfen.

+1

Gzipping wird nicht helfen, wenn er immer noch das XML auf diese Weise erstellt. Das Problem liegt nicht in der Übertragung der Daten, sondern in der Tatsache, dass sie vor dem Senden im Speicher zwischengespeichert wird. Und es gibt keine praktische Grenze für ein HTTP-GET. Vor allem wenn man bedenkt, dass Sie unterbrochene Downloads fortsetzen können und wir keine Ahnung haben, welche Art von Netzwerk er sendet. Könnte ein Gigabit-Ethernet sein! – Josh

1

Sie sollten XML nicht mithilfe von Zeichenfolgenmanipulation erstellen.

Stattdessen sollten Sie die XmlTextWriter, XmlDocument oder (in .NET 3.5) XElement Klassen verwenden, um eine XML-Struktur im Speicher zu bauen, dann schreiben Sie direkt an Response.OutputStream ein XmlTextWriter verwenden.

Schreiben Sie direkt in eine XmlTextWriter, die Response.OutputStream wra effizient sein wird (Sie werden nie einen ganzen Elementbaum im Speicher auf einmal haben), wird aber etwas komplizierter.

Auf diese Weise haben Sie nie eine einzelne Zeichenfolge (oder ein Array), die das gesamte Objekt enthält, und sollten daher OutOfMemoryExceptions vermeiden.

+1

XmlDocument und XElement werden die gleichen (tatsächlich schlechter) Speicherprobleme als String-Manipulation aufweisen! Das Erstellen einer großen XML-Struktur kann nur mit der XmlWriter-API erfolgen. – Josh

+1

Sie können immer noch aus dem Speicher Ausnahmen erhalten, wenn Sie nicht genügend zusammenhängende Speicher haben. Es ist vernünftiger, den Ansatz zum Schreiben in einen Stream zu ändern. –

+0

@Josh: Nein. Nur 'String' und' Array' werden große Blöcke von _contiguous_ memory zuweisen. – SLaks

1

Hatte ein ähnliches Problem, hoffe, dass dies jemandem helfen wird. Meine anfängliche Code war:

var serializer = new XmlSerializer(type); 
string xmlString; 

using (var writer = new StringWriter()) 
{ 
    serializer.Serialize(writer, objectData, sn); // OutOfMemoryException here 
    xmlString = writer.ToString(); 
} 

Ich landete replaceing String mit Memorystream und dies mein Problem gelöst

using (var mem = new MemoryStream()) 
{ 
    serializer.Serialize(mem, objectData, sn); 
    xmlString = Encoding.UTF8.GetString(mem.ToArray()); 
}