Freigeben über


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

Dieser Artikel hilft Ihnen bei der Problembehandlung von Out of Memory-Fehlern in ASP.NET.

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

Problembeschreibung

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

Bevor wir die Details zur Problembehandlung behandeln OutOfMemoryException, ist es wichtig zu verstehen, was dieses Problem verursacht. Im Gegensatz zu den, was viele Entwickler glauben, wirkt sich die Menge der installierten RAM nicht auf die Möglichkeit einer OutOfMemoryException. Ein 32-Bit-Betriebssystem kann 4 GB virtuellen Adressraum adressieren, unabhängig davon, wie viel physischer Arbeitsspeicher im Feld installiert ist. Davon sind 2 GB für das Betriebssystem (Kernelmodusspeicher) reserviert und 2 GB für Benutzermodusprozesse zugewiesen. Der für den Kernelmodus-Speicher zugewiesene 2 GB wird für alle Prozesse freigegeben, aber jeder Prozess erhält einen eigenen 2 GB Adressraum für den Benutzermodus. Es wird davon ausgegangen, dass Sie nicht mit aktiviertem /3gb Switch ausgeführt werden.

Wenn eine Anwendung Arbeitsspeicher verwenden muss, reserviert sie einen Teil des virtuellen Adressraums und führt dann einen Commit des Speichers aus diesem Block durch. Genau das, was der Garbage Collector (GC) von .NET Framework tut, wenn er Arbeitsspeicher benötigt, um die verwalteten Heaps zu vergrößern. Wenn die GC ein neues Segment für den Heap für kleine Objekte benötigt (wobei Sich Objekte kleiner als 85 KB befinden), wird eine Zuordnung von 64 MB erstellt. Wenn ein neues Segment für den Heap für große Objekte benötigt wird, wird eine Zuordnung von 16 MB ausgeführt. Diese großen Zuordnungen müssen aus zusammenhängenden Blöcken des 2 GB Adressraums erfüllt sein, mit dem der Prozess arbeiten muss. Wenn das Betriebssystem die Anforderung des GC für einen zusammenhängenden Speicherblock nicht erfüllen kann, tritt ein System.OutOfMemoryException (OOM) auf.

Notiz

Ein 32-Bit-Prozess, der auf einem 64-Bit-Betriebssystem ausgeführt wird, kann 4 GB Benutzermodusspeicher 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 es tritt normalerweise erst auf, wenn der Prozess fast 3 GB private Bytes verwendet.

Es gibt zwei Gründe, warum Sie möglicherweise eine OOM-Bedingung sehen.

  1. Ihr Prozess verwendet viel Arbeitsspeicher (in der Regel über 800 MB in einer 32-Bit-Umgebung.)
  2. Der virtuelle Adressraum ist fragmentiert und reduziert die Wahrscheinlichkeit, 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 von System.OutOfMemoryExceptions" in ASP.NET.

Wenn ein OOM auftritt, bemerken Sie möglicherweise ein oder mehrere der folgenden Symptome:

Wenn es darum geht, die Ursache für eine OOM-Bedingung zu bestimmen, arbeiten Sie tatsächlich daran, die Ursache für eine hohe Speichersituation oder einen fragmentierten Adressraum zu bestimmen. Obwohl wir nicht alle möglichen Ursachen dieser 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 Auflösungen zum Auflösen dieser Ursachen beschrieben.

Zeichenfolgenverkettung

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

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

Fragmentierung im verwalteten Heap

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

Wir haben daran gearbeitet, die OOM-Bedingungen aufgrund der Anheftung seit .NET Framework 1.0 zu minimieren. Inkrementelle Verbesserungen wurden in jeder Version vorgenommen. Es gibt jedoch weiterhin Entwurfsmuster, die Sie implementieren können, die von Vorteil sein werden, wenn Sie Objekte anheften müssen.

Fragmentierung im Virtuellen Adressraum (VA)

Jeder Prozess verfügt über einen bestimmten Arbeitsspeicher, der ihm zugeordnet ist, und dieser Speicher stellt den VA-Speicherplatz für den Prozess dar. Wenn der VA-Raum fragmentiert wird, erhöht sich die Wahrscheinlichkeit, dass die GC keinen großen Block zusammenhängender Speicher abrufen kann, um die verwalteten Heaps zu vergrößern. Und es kann zu einer OOM-Bedingung führen.

Fragmentierung im VA-Raum wird häufig durch ein oder mehrere der folgenden Szenarien verursacht:

  • Laden der gleichen Assemblys in mehrere Anwendungsdomänen.

    Wenn Sie eine Assembly in mehreren Anwendungen verwenden müssen, die im selben Anwendungspool ausgeführt werden, benennen Sie die Assembly stark, 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, auf das <compilation>truefestgelegt ist.

    • 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 immer im Produkt deaktiviert ist. Weitere Informationen finden Sie unter deployment Element (ASP.NET Settings Schema).
  • Verwendung von Skripts in eXtensible Stylesheet Language (XSL)-Transformationen oder Erstellen XmlSerializers.

    In diesem Fall werden dynamische Assemblys, die durch Xslt-Skripts (Extensible Stylesheet Language Transformations) verursacht werden, oder XmlSerializers.

Zurückgeben großer Datenmengen

Wenn Sie Daten aus einer Datenbank oder einer anderen Datenquelle verwenden, ist es wichtig, die zurückgegebene Datenmenge einzuschränken. 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, ist kein guter Ansatz. Dies kann leicht zu einem hohen Arbeitsspeicher führen und zu einer OOM-Bedingung führen. Ein Benutzer kann eine ähnliche Abfrage starten, ist eine weitere gängige Möglichkeit zum Erstellen einer hohen Speichersituation. 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.

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

Es ist ebenso wichtig, sicherzustellen, dass Sie keine großen Daten anzeigen, was zu UI-Elementen wie dem GridView-Steuerelement führt. Neben dem für die zurückgegebenen Daten erforderlichen Speicher verbrauchen Sie auch große Datenmengen in Zeichenfolgen und in UI-Elementen, die zum Rendern der Ergebnisse erforderlich sind. Durch die Implementierung von Auslagerungs- und Überprüfungseingaben, sodass große Datenmengen nicht 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 von Anwendungen. Es sollte aber nie in einer Produktionsumgebung verbleiben. ASP.NET Ablaufverfolgung verwendet Datenstrukturen, z DataTables . B. zum Speichern von Ablaufverfolgungsinformationen, und im Laufe der Zeit können sie zu einer hohen Arbeitsspeicherbedingung führen, die zu OOM führen kann.

Die Ablaufverfolgung sollte in einer Produktionsumgebung deaktiviert werden. Sie können dies tun, indem Sie das enabled Attribut des <trace> Elements auf "false" in der Datei "web.config " festlegen. Wenn Sie die Einzelhandelsbereitstellung aktivieren, wird <deploy retail="true" /> auch die Ablaufverfolgung in Ihren Anwendungen deaktiviert.

Systemeigene Ressourcen durchlecken

Viele verwaltete Ressourcen nutzen auch systemeigene Ressourcen. Da die GC systemeigene Ressourcen nicht bereinigt, ist ein Entwickler für die Implementierung und Aufrufen der Dispose-Methode verantwortlich, um systemeigene Ressourcen zu bereinigen. Wenn Sie einen Typ verwenden, der die IDisposable Schnittstelle implementiert und die Methode nicht aufruft Dispose , riskieren Sie, dass systemeigene Ressourcen verloren gehen und eine OOM-Bedingung verursacht wird.

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