Behandeln von Problemen mit nicht genügend Arbeitsspeicher (System.OutOfMemoryException) in ASP.NET

Dieser Artikel hilft Ihnen bei der Behandlung von Fehlern mit nicht genügend Arbeitsspeicher in ASP.NET.

              Originale Produktversion: ASP.NET
Ursprüngliche KB-Nummer: 2020006

Symptome

Eines der häufigsten Probleme, die wir in Microsoft Customer Support Services sehen, sind OutOfMemoryException Szenarien. Daher haben wir eine Sammlung von Ressourcen zusammengestellt, um die Problembehandlung zu unterstützen und die Ursache von Speicherproblemen zu identifizieren.

Bevor wir die Details zur Problembehandlung eines OutOfMemoryExceptionbehandeln, ist es wichtig zu verstehen, was dieses Problem verursacht. Im Gegensatz zu dem, was viele Entwickler glauben, wirkt sich die Menge des installierten ARBEITSSPEICHERs nicht auf die Möglichkeit eines aus OutOfMemoryException. Ein 32-Bit-Betriebssystem kann 4 GB virtuellen Adressraum adressieren, unabhängig davon, wie viel physischer Arbeitsspeicher in der Box installiert ist. Davon sind 2 GB für das Betriebssystem (Kernelmodusspeicher) und 2 GB für Benutzermodusprozesse reserviert. Die 2 GB, die dem Kernelmodusspeicher zugeordnet sind, werden von allen Prozessen gemeinsam genutzt, aber jeder Prozess erhält einen eigenen Adressraum von 2 GB im Benutzermodus. Es wird davon ausgegangen, dass Sie nicht mit aktiviertem /3gb Switch ausführen.

Wenn eine Anwendung Arbeitsspeicher verwenden muss, reserviert sie einen Teil des virtuellen Adressraums und committet dann Arbeitsspeicher aus diesem Block. Dies ist genau das, was der Garbage Collector (GC) des .NET Framework tut, wenn er Arbeitsspeicher benötigt, um die verwalteten Heaps zu vergrößern. Wenn die GC ein neues Segment für den kleinen Objektheap benötigt (in dem sich Objekte kleiner als 85 KB befinden), wird eine Zuordnung von 64 MB durchgeführt. Wenn ein neues Segment für den großen Objektheap benötigt wird, erfolgt eine Zuordnung von 16 MB. Diese großen Zuordnungen müssen aus zusammenhängenden Blöcken des 2 GB Adressraums, mit denen der Prozess arbeiten muss, erfüllt werden. Wenn das Betriebssystem die Anforderung der GC für einen zusammenhängenden Speicherblock nicht erfüllen kann, tritt ein System.OutOfMemoryException (OOM) auf.

Hinweis

Ein 32-Bit-Prozess, der auf einem 64-Bit-Betriebssystem ausgeführt wird, kann 4 GB Arbeitsspeicher im Benutzermodus adressieren, und ein 64-Bit-Prozess, der auf einem 64-Bit-Betriebssystem ausgeführt wird, kann 8 TB Benutzermodusspeicher adressieren, sodass ein OOM auf einem 64-Bit-Betriebssystem nicht wahrscheinlich ist. Es ist möglich, ein OOM in einem 32-Bit-Prozess zu erleben, der auf einem 64-Bit-Betriebssystem ausgeführt wird, aber dies tritt in der Regel erst auf, wenn der Prozess fast 3 GB private Bytes verwendet.

Es gibt zwei Gründe, warum eine OOM-Bedingung angezeigt wird.

  1. Ihr Prozess verwendet viel Arbeitsspeicher (in der Regel über 800 MB in einer 32-Bit-Umgebung).
  2. Der virtuelle Adressraum ist fragmentiert, wodurch die Wahrscheinlichkeit verringert wird, dass eine große, zusammenhängende Zuordnung erfolgreich ist.

Es ist auch möglich, eine OOM-Bedingung aufgrund einer Kombination von 1 und 2 zu sehen. Weitere Informationen finden Sie unter Problembehandlung bei System.OutOfMemoryExceptions in ASP.NET.

Wenn ein OOM auftritt, können Sie eines oder mehrere der folgenden Symptome bemerken:

Wenn es darum geht, die Ursache für eine OOM-Bedingung zu ermitteln, arbeiten Sie tatsächlich daran, die Ursache für eine Hohe Speichersituation oder einen fragmentierten Adressraum zu ermitteln. Obwohl wir nicht alle möglichen Ursachen für diese Situationen dokumentieren können, gibt es einige häufige Ursachen, die wir regelmäßig sehen.

In den folgenden Informationen werden häufige Ursachen für OOM-Bedingungen und die Lösungen zur Behebung jeder dieser Ursachen beschrieben.

Zeichenfolgenverknüpfung

Zeichenfolgen in einer verwalteten Anwendung (eine Anwendung, die mithilfe der .NET Framework geschrieben wird) sind unveränderlich. Wenn einer Zeichenfolge ein neuer Wert zugewiesen wird, wird eine Kopie der vorhandenen Zeichenfolge erstellt. Und der neue Wert wird der neuen Zeichenfolge zugewiesen. Dies verursacht in der Regel keine Probleme. Wenn jedoch eine große Anzahl von Zeichenfolgen verkettet wird, führt dies zu viel mehr Zeichenfolgenzuordnungen, als ein Entwickler erkennen könnte. Und es kann zu Speicherwachstum und OOM-Bedingungen führen.

Um OOM aufgrund einer Zeichenfolgenverkettung zu vermeiden, stellen Sie sicher, dass Sie die StringBuilder -Klasse verwenden. Weitere Informationen finden Sie unter Verbessern der Leistung der Zeichenfolgenverkettung in Visual C#.

Fragmentierung im verwalteten Heap

Der Garbage Collector (GC) in einer verwalteten Anwendung komprimiert die Heaps, um die Fragmentierung zu reduzieren. Es ist jedoch möglich, Objekte in einer verwalteten Anwendung anzuheften. Angeheftete Objekte können während der Heapkomprimierung nicht verschoben werden. Dies würde die Adresse ändern, unter der sich das Objekt befindet. Wenn eine Anwendung eine große Anzahl von Objekten anheftet und/oder Objekte für eine lange Zeit anheftet, kann dies zu Einer Fragmentierung im verwalteten Heap führen. Dies kann dazu führen, dass der GC den verwalteten Heap häufiger vergrößert und eine OOM-Bedingung verursacht.

Seit dem .NET Framework 1.0 haben wir daran gearbeitet, OOM-Bedingungen aufgrund von Anheftungen zu minimieren. Inkrementelle Verbesserungen wurden in jeder Version vorgenommen. Es gibt jedoch weiterhin Entwurfsmuster, die Sie implementieren können, die von Vorteil sind, wenn Sie Objekte anheften müssen.

Fragmentierung im Virtuellen Adressraum (VA)

Jedem Prozess ist eine bestimmte Menge an Arbeitsspeicher zugeordnet, und dieser Arbeitsspeicher stellt den VA-Speicherplatz für den Prozess dar. Wenn der Va-Bereich fragmentiert wird, erhöht sich die Wahrscheinlichkeit, dass die GC keinen großen Block zusammenhängenden Speichers abrufen kann, um die verwalteten Heaps zu vergrößern. Und es kann zu einer OOM-Bedingung führen.

Die Fragmentierung im VA-Bereich wird häufig durch eines oder mehrere der folgenden Szenarien verursacht:

  • Laden der gleichen Assemblys in mehrere Anwendungsdomänen.

    Wenn Sie eine Assembly in mehr als einer Anwendung verwenden müssen, die im selben Anwendungspool ausgeführt wird, benennen Sie die Assembly mit starkem Namen, und installieren Sie sie im GAC. Dadurch stellen Sie sicher, dass die Assembly nur einmal in den Prozess geladen wird.

  • Ausführen einer Anwendung in der Produktion mit dem Debug-Attribut des Elements, das <compilation> auf festgelegt ist true.

    • Das Debug-Attribut des Elements sollte in der <compilation> Produktion sein false .
    • Sie können die <deploy retail="true" /> Konfiguration verwenden, um sicherzustellen, dass das Debuggen im Produkt immer deaktiviert ist. Weitere Informationen finden Sie unter deployment Element (ASP.NET Settings Schema).
  • Die Verwendung von Skripts in eXtensible Stylesheet Language (XSL) dient zum Transformieren oder Erstellen von XmlSerializers.

    In diesem Fall dynamische Assemblys, die durch xslt-Skripting (Extensible Stylesheet Language Transformations) oder XmlSerializersverursacht werden.

Zurückgeben großer Datenmengen

Wenn Sie Daten aus einer Datenbank oder einer anderen Datenquelle verwenden, ist es wichtig, die menge der zurückgegebenen Daten zu begrenzen. Beispielsweise ist das Zwischenspeichern eines Abfrageergebnisses, das eine gesamte Datenbanktabelle zurückgibt, um die Kosten für das Abrufen von Datenteilen aus der Datenbank bei Bedarf zu vermeiden, kein guter Ansatz. Dies kann leicht zu einem hohen Arbeitsspeicher führen und zu einer OOM-Bedingung führen. Einem Benutzer das Starten einer ähnlichen Abfrage zu erlauben, ist eine weitere gängige Möglichkeit, eine Situation mit hohem Arbeitsspeicher zu erstellen. Geben Sie beispielsweise alle Mitarbeiter in einem Unternehmen oder alle Kunden im Bundesstaat Texas mit einem Nachnamen zurück, der mit dem Buchstaben S beginnt.

Begrenzen Sie immer die Datenmenge, die von einer Datenbank zurückgegeben werden kann. Lassen Sie keine Abfragen zu, z SELECT * FROM. . . . B. weil Sie dann keine Kontrolle darüber haben, wie viele Daten auf Ihrer Seite angezeigt werden.

Ebenso wichtig ist es, sicherzustellen, dass Sie kein großes Datenergebnis in Ui-Elementen wie dem GridView-Steuerelement anzeigen. Neben dem für die zurückgegebenen Daten erforderlichen Arbeitsspeicher nutzen Sie auch große Datenmengen in Zeichenfolgen und ui-Elementen, die zum Rendern der Ergebnisse erforderlich sind. Indem Sie Paging implementieren und Eingaben überprüfen, damit keine großen Datenmengen zurückgegeben werden, können Sie dieses Problem vermeiden.

Ausführen in einer Produktionsumgebung mit aktivierter Ablaufverfolgung

ASP.NET-Ablaufverfolgung ist ein leistungsstarkes Feature für die Problembehandlung bei Anwendungen. In einer Produktionsumgebung sollte dies jedoch niemals aktiviert werden. ASP.NET Ablaufverfolgung verwendet Datenstrukturen wie DataTables zum Speichern von Ablaufverfolgungsinformationen und kann im Laufe der Zeit zu einer hohen Arbeitsspeicherauslastung führen, die zu OOM führen kann.

Die Ablaufverfolgung sollte in einer Produktionsumgebung deaktiviert werden. Dazu legen Sie das enabled -Attribut des <trace> Elements in Ihrer web.config-Datei auf false fest. Wenn Sie die Einzelhandelsbereitstellung mithilfe von <deploy retail="true" /> aktivieren, wird auch die Ablaufverfolgung in Ihren Anwendungen deaktiviert.

Verlust nativer Ressourcen

Viele verwaltete Ressourcen nutzen auch native Ressourcen. Da die GC keine nativen Ressourcen sauber, ist ein Entwickler für die Implementierung und den Aufruf der Dispose-Methode verantwortlich, um native Ressourcen zu sauber. Wenn Sie einen Typ verwenden, der die IDisposable Schnittstelle implementiert, und Sie die Dispose -Methode nicht aufrufen, riskieren Sie, dass native Ressourcen verloren gehen und eine OOM-Bedingung verursacht wird.

Diese Objekte sollten die iDisposable -Schnittstelle implementieren, und Sie sollten die Dispose -Methode für diese Objekte aufrufen, wenn Sie sie nicht mehr benötigen.