2010-04-22 6 views
5

Die Situation ist, dass ich einen WCF-Aufruf an einen Remote-Server mache, der ein XML-Dokument als Zeichenfolge zurückgibt.Maximieren des größten zusammenhängenden Speicherblocks im Large Object Heap

Die meiste Zeit ist dieser Rückgabewert ein paar K, manchmal ein paar Dutzend K, sehr gelegentlich ein paar hundert K, aber sehr selten könnte es mehrere Megabyte sein (erstes Problem ist, dass es keine Möglichkeit für mich gibt)).

Es sind diese seltenen Gelegenheiten, die Kummer verursachen. Ich bekomme einen Stack-Trace, die beginnt:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. 
    at System.Xml.BufferBuilder.AddBuffer() 
    at System.Xml.BufferBuilder.AppendHelper(Char* pSource, Int32 count) 
    at System.Xml.BufferBuilder.Append(Char[] value, Int32 start, Int32 count) 
    at System.Xml.XmlTextReaderImpl.ParseText() 
    at System.Xml.XmlTextReaderImpl.ParseElementContent() 
    at System.Xml.XmlTextReaderImpl.Read() 
    at System.Xml.XmlTextReader.Read() 
    at System.Xml.XmlReader.ReadElementString() 
    at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMDRQuery.Read2_getMarketDataResponse() 
    at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2.Deserialize(XmlSerializationReader reader) 
    at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) 
    at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) 

Ich habe um zu lesen, und es ist, weil das Large Object Heap ist einfach zu stark fragmentiert bekommen, so der sich in das Gespräch mit einem schnellen Scheck StringBuilder.EnsureCapacity nur bewirkt, dass die OutOfMemoryException früher ausgelöst werden (und weil ich rate, was benötigt wird, benötigt es möglicherweise nicht so viel, so dass mein Check mehr Probleme verursacht, als es löst). Einige opinions sind, dass ich nicht viel dagegen tun kann.

Einige der Fragen, die ich mich gefragt habe:

  • Verwenden weniger Speicher - haben Sie auf Lecks überprüft? Ja. Die Speicherauslastung steigt und sinkt, aber es gibt kein grundlegendes Wachstum, das dies garantiert. Manchmal ist es nicht gelungen, zu diesem Zeitpunkt war es erfolgreich.
  • Übertragung kleine Mengen nicht möglich ist, ist dies ein Dritte Web-Service, über die ich keine Kontrolle habe (oder zumindest es eine lange Zeit in der Zwischenzeit zu lösen, nehmen würde ich habe immer noch ein Problem)
  • Können Sie etwas mit dem LOH machen, damit es weniger wahrscheinlich ausfallen wird? ... jetzt ist dies der fruchtbarste Weg. Es ist ein 32-Bit-Prozess (es muss für verschiedene politische, technische und langweilige Gründe sein), aber es gibt normalerweise Hunderte von Meg frei (Vielfache der größten Menge, für die wir Fehler gesehen haben).
  • Können wir die LOH überwachen? Mit perfmon kann ich die Größe der Heaps verfolgen, aber ich glaube nicht, dass es eine Möglichkeit gibt, den größten verfügbaren zusammenhängenden Speicherblock zu überwachen.

Frage ist: irgendwelche Ratschläge oder Vorschläge für Dinge zu versuchen?

Antwort

5

Sie könnten das Transfermode Eigentum Ihrer Bindung zu sehen, ob Sie die Anforderungen erfüllen ändern es von seinem Standardwert „Buffered“, zu „gestreamt“ oder „StreamedResponse“ überprüfen.

Auch die Werte für MaxBufferPoolSize und MaxBufferSize überprüfen. Durch die Erhöhung der Größe der verwendeten internen Puffer kann die Speichernutzung verbessert werden, insbesondere bei der Verarbeitung großer Nachrichten.

maxReceivedMessageSize ist auch wahrscheinlich bereits festgelegt, wenn Sie große Nachrichten empfangen, aber ich würde diesen Wert auch überprüfen.

Ich habe einen der oben genannten Werte gesehen, wenn der Schwellenwert überschritten wird und eine obskure, speicherbezogene Nachricht nicht angezeigt wird. Die ursprüngliche Ausnahme wurde tatsächlich durch die Nachricht ausgeblendet, die meiner Anwendung angezeigt wurde.Die Aktivierung von WCF Tracing half dabei, das Problem zu diagnostizieren und den tatsächlichen Fehler zu sehen - ich musste den Wert von einem oder mehreren der obigen Bindungseigenschaften erhöhen.

Ich habe nicht das Gefühl für die Bindung Ihrer Verwendung von Ihrem Beitrag, aber ich glaube, dass diese Einstellungen für die wichtigsten gemeinsamen sind. Schauen Sie sich zum Beispiel die MSDN-Dokumentation unter basicHttpBinding an.

Wenn es wirklich LOH Fragmentierung ist, gibt es nichts zu tun, sobald die Tuning-Bemühungen erschöpft sind. Rolling Recycling der Anwendung könnte erforderlich sein, um es zu mildern (ich hasse es zu empfehlen), aber wenn Sie andere Anstrengungen erschöpft haben, könnten Sie damit belassen werden.

+0

Ändern der Bindung ist eine gute Idee - ich werde es versuchen. Ein rollender Recycling war unser letzter Ausweg ... – Unsliced

+0

wir hatten das Glück, alle Probleme mit großen Dokumentenverarbeitung entweder durch Code-Verbesserungen (wir besitzen beide Endpunkte obwohl), oder verbindliche Änderungen, zumindest um uns durch zu kommen zu einem regelmäßig geplanten Wartungs-Recycling (aufgrund von Patches, Feature Release, etc.). @ Steven's Idee der Verwendung von Windbg für Heap-Analyse kann auch Vorteile bringen. Versuchen Sie http://blogs.msdn.com/tess/ und Sie werden gute Informationen von Tess Ferrandez finden, wie Sie hier anfangen können. Ausgezeichnete Labore! Viel Glück! –

1

Ich denke, Ihr Problem Könnte eine Versammlung Leck durch den Einsatz XmlSerializer verursacht werden und nicht einer von zwei Konstrukteuren, wie in dieser MSDN article angegeben:

Leistung zu erhöhen, die XML Serialisierung Infrastruktur dynamisch erzeugt Baugruppen zu serialisieren und deserialisieren angegebenen Typen. Die Infrastruktur findet und wiederverwendet diese Baugruppen. Dieses Verhalten nur auftritt, wenn die folgenden Bauer mit:

XmlSerializer.XmlSerializer (Typ)

XmlSerializer.XmlSerializer (Type, String)

Wenn Sie irgendeine der anderen Bauer, mehrere Versionen der gleichen Baugruppe werden generiert und nie entladen, was zu einem Speicher Leck und schlechte Leistung führt.

Schön, huh. Die Antwort besteht darin, Ihren XmlSerializer zwischenzuspeichern (vorausgesetzt, Sie erstellen ihn sogar).

Um wirklich herauszufinden, müssen Sie tun, was Tess sagt Ihnen zu tun. Sie ist ein verrücktes Genie.

1

Wenn möglich würde ich für einen stream-basierten Ansatz gehen und einen Xml Parser in Kombination verwenden, der Ihnen auch eine bessere Leistung geben sollte.

Wenn Sie nicht unbedingt WCF verwenden müssen, können Sie Ihre eigene HttpRequest schreiben und dann die Antwort an den XmlDeserializer übergeben und dann die Antwort wie folgt analysieren. Es gibt Ihnen möglicherweise mehr Kontrolle und Einblick, wo das Problem tatsächlich auftritt. Sie können auch mit einem Scheindienst experimentieren, der sehr große Dokumente des gesuchten Typs zurückgibt. Wir hatten auch viele Kopfschmerzen mit der LOH Fragmentierung, so dass ich deine Schmerzen fühle.

Ein Problem, das beim Erstellen von Puffern auftrat .NET neigt dazu, die Kapazität jedes Mal zu verdoppeln, wenn der Puffer voll ist, was Speicherfragmentierung verursacht, da für ein Dokument der Größe 10 MB Speicher in vielen Schritten zugeordnet werden muss. Wenn Sie die benötigte Puffergröße im Voraus kennen, ist es effizienter, sie sofort zuzuweisen. Wenn Sie also wissen, wie groß das eingehende Dokument sein wird, können Sie einen StringBuilder mit genau dieser Größe erstellen.

2

Ich kann keine der WCF-spezifischen Probleme beheben, aber wenn Sie LOH-Speicherplatz für einen 32-Bit-Prozess maximieren müssen, sollten Sie die Anwendung large address aware ausführen und auf 64-Bit ausführen. Ein großer adressierbarer 32-Bit-Prozess kann den gesamten 4-GB-Adressraum adressieren, wenn er unter 64-Bit-Windows ausgeführt wird. Dadurch erhalten Sie einen beträchtlichen Speicherbereich über dem normalerweise vom Prozess verwendeten Adressraum.

Verwandte Themen