Aspnetcore: Asp.net Core sammelt keinen Müll

Erstellt am 21. März 2017  ·  136Kommentare  ·  Quelle: dotnet/aspnetcore

Ich kann nicht verstehen, warum der Asp.net-Kern keinen Müll zu sammeln scheint. Letzte Woche habe ich einen Webdienst für ein paar Tage laufen lassen und meine Speicherauslastung hat 20 GB erreicht. GC scheint nicht richtig zu funktionieren. Um dies zu testen, habe ich eine sehr einfache Webmethode geschrieben, die eine große Sammlung von Zeichenfolgen zurückgibt. Die Anwendung verbrauchte zu Beginn nur 124 MB, aber mit jedem Aufruf der Webmethode wurde die Speichernutzung immer höher, bis sie 411 MB erreichte. Es wäre höher geworden, wenn ich die Webmethode weiter aufgerufen hätte. Aber ich beschloss, mit dem Testen aufzuhören.

Mein Testcode war dieser:

`

[HttpGet]
öffentliche asynchrone Aufgabe> TestGC() {
const string message = "TEST";
return Enumerable.Repeat (Nachricht, 100000000);
}
`

Obwohl ich vielleicht etwas übersehe... Meines Wissens nach sollte die Speichernutzung nicht mit jedem Aufruf dieser Methode steigen. Nachdem das Objekt erstellt und an die Benutzeroberfläche gesendet wurde, sollte der Speicher freigegeben worden sein.

Wie Sie auf dem Screenshot unten sehen können, wurde der Speicher auch nach dem Aufruf des GC nicht freigegeben.
netcorescreenshot

Danke für die Hilfe!
Jay

investigate

Hilfreichster Kommentar

Irgendwelche Neuigkeiten dazu? Ich verwende Core 2 über Net Framework und dies geschieht immer noch. Jeder Aufruf an einen _Controller_ erhöht den verwendeten Speicher, aber er geht nie unter. (_Ich habe die WebApi-Vorlage verwendet_)

Alle 136 Kommentare

@rynowak

Obwohl ich vielleicht etwas übersehe... Meines Wissens nach sollte die Speichernutzung nicht mit jedem Aufruf dieser Methode steigen. Nachdem das Objekt erstellt und an die Benutzeroberfläche gesendet wurde, sollte der Speicher freigegeben worden sein.

Der große Objekthaufen beißt Sie wahrscheinlich hier. Wenn Sie Objekte mit einer Größe von > 85 KB zuweisen, werden sie in den LOH gestellt und sehr selten komprimiert . Siehe http://stackoverflow.com/questions/8951836/why-large-object-heap-and-why-do-we-care für weitere Details (oder https://github.com/dotnet/coreclr/blob/master /Documentation/botr/garbage-collection.md#design-of-allocator wenn Sie tiefer gehen möchten).

Ich kann nicht verstehen, warum der Asp.net-Kern keinen Müll zu sammeln scheint. Letzte Woche habe ich einen Webdienst für ein paar Tage laufen lassen und meine Speicherauslastung hat 20 GB erreicht

Was macht Ihr Dienst, dass er so große Objekte erstellt? Sie sollten versuchen, einen Speicherauszug zu erstellen, bevor er zu groß wird, der Ihnen deutlich zeigt, welche Objekte herumliegen und warum er festgehalten wird (Sie können Visual Studio verwenden, um sich Dumps oder ein fortgeschritteneres Tool wie windbg oder perfview anzusehen).

Versuchen Sie, das Array von Anfang an zuzuweisen, anstatt Enumerable.Repeat aufzurufen
oder komprimieren Sie den Speicher mit GCSettings.LargeObjectHeapCompactionMode (unterstützt in .Net Standard)

Danke @davidfowl und @MhAllan für die Antworten. Aber dieses Beispiel war erfunden. Ich wollte nur etwas, das eine merkliche Menge an Speicher verbraucht, damit ich einen Screenshot machen kann. Die Wahrheit ist, dass dies bei jeder Anwendung geschieht, unabhängig von der Größe des betreffenden Objekts. Und um Ihre Frage @davidfowl zu beantworten, mein Dienst hat nur einige Daten mit dapper aus der Datenbank gezogen und das resultierende Objekt zurückgegeben. Es war eine Datenzeile für jeden Anruf. Es dauerte also ein paar Tage, bis die Erinnerung auf diese Menge angewachsen war. Ich habe tatsächlich versucht, die DB zu testen, als ich auf diese Besonderheit gestoßen bin. Ich hatte eine kleine Konsolen-App geschrieben, die die Methode immer wieder aufrief.

@zorthgo sicher, dass es nicht Dapper ist? Wenn Sie Ihre Skripte erstellen, indem Sie wie in PHP Parameter direkt in Ihre SQL-Skripte einfügen, erhalten Sie am Ende viele zwischengespeicherte SQL-Skripte. So macht Dapper es
https://github.com/StackExchange/Dapper/blob/fe5c270aceab362c936456087a830e6fe1603cac/Dapper/SqlMapper.cs
Sie sollten einen Speicherprofiler verwenden, um festzustellen, was Verweise auf zugewiesenen Speicher enthält. Visual Studio 2017 sollte Ihnen dabei helfen können, vor und nach mehreren Aufrufen Ihrer App einfach einige Momentaufnahmen aus dem Speicher zu erstellen und diese zu vergleichen.

@zorthgo Ja, das habe ich auch gesehen. Ich habe den Servicestack in meiner .net-Core-Konsolen-App verwendet und jedes Mal, wenn ich die API anrufe, stieg die Speichernutzung um massive 50 MB. Ich nahm an, dass es sich um einen VS2017-Bug handelte, bestätigte dann aber die hohe Auslastung im Task-Manager. Wie zorthgo feststellte, stieg die Speichernutzung durch einfache Aufrufe von api erheblich an und schien keinen Speicher freizugeben.

Tritt dies nur auf ASP.NET Core auf .NET Core auf oder ist es auch ein Problem mit ASP.NET Core auf .NET Framework?

Können Sie eine ähnliche Anwendung mit MVC 5 (auf System.Web) schreiben und überprüfen, ob Sie nicht dasselbe Verhalten sehen?

Ich kann mit diesem Problem in seinem aktuellen Zustand keine Fortschritte erzielen.

In meiner Instanz habe ich nur das Zielframework .NetCoreApp 1.1 verwendet und meine Konsolen-App hat auf ein Objektmodell in einem freigegebenen Projekt verwiesen.

Nicht sicher, ob dies jemandem hilft. eine Beispiel-App, die hellorequest aufruft. In dieser App beträgt der Startspeicher 85 MB, dann gelang es mir durch wiederholte Anfrage, die Speichernutzung auf etwa 145 MB zu erhöhen. Es fällt manchmal auf 125 MB zurück, bleibt dann aber dort. Ich bin mir nicht sicher, ob dies ein normales Verhalten ist, da ich nicht an .Net Core-Konsolen-Apps gewöhnt bin. Ich bin immer davon ausgegangen, dass ich etwas falsch mache oder nicht richtig instanziiere.

https://drive.google.com/open?id=0B0Gm-m-z_U84TU5keWFTMzc1ZWc

Das gleiche Problem hier bei einer Asp.Net Core-Anwendung, die in der Produktion mit 3000-5000 aktiven Benutzern bereitgestellt wird. Der Speicher auf dem Server wurde gestern auf 15 GB erhöht versuchen Sie herauszufinden, was das Problem ist.

Hat jemand einen Speicherauszug erstellt und sich angesehen, was den gesamten Speicher in Ihren speziellen Anwendungen belegt?

@davidfowl @Pinox
Ich arbeite in einem großen Unternehmen und wir möchten ein neues Projekt mit ASP.NET Core starten, aber als ich dieses Problem sah, hatte ich Angst :besorgt: . Dies ist ein kritisches Problem und kann den Lebenszyklus unseres Projekts blockieren.

Also bitte, bezieht es sich auf ASP.NET Core oder .NET Core (CoreCLR)? Wir werden auf Full .NET (4.6) abzielen, deshalb frage ich.

@ikourfaln In meinem Fall habe ich die .net-Core-Konsolen-App, den Servicestack (.net-Core-Version) und Kestrel verwendet. Das Seltsame ist, dass die Speichernutzung auf ein Niveau ansteigt, dann plötzlich aufhört und nicht wieder ansteigt. Ich denke, am besten ist es, es auf Ihrer Seite mit kleinen Stichproben zu testen und das Verhalten zu überprüfen.

Vielleicht kann @zorthgo auf seiner Seite überprüfen, ob er ein ähnliches Verhalten in diesem Gedächtnis sieht, das bis zu einem bestimmten Grad verwendet wird und dann aufhört zuzunehmen, da dies das Verhalten ist, das ich sehe. Ich habe meine Beispiel-App aktualisiert, um das @zorthgo- Beispiel einzuschließen, und ich sehe nicht, dass der Speicher wegläuft. Es geht hoch, hört aber irgendwann auf.

Ich habe die Quelle etwas geändert:

Öffentliches Objekt Any (TestGC-Anforderung)
{
const string message = "TEST";
Enumerable.Repeat (Nachricht, 100000) zurückgeben;
}

@ Pinox
Danke, ich werde das Verhalten auf meiner Seite überprüfen.

Was ist mit diesem Fehler in 2.0?

Irgendwelche Neuigkeiten dazu? Ich verwende Core 2 über Net Framework und dies geschieht immer noch. Jeder Aufruf an einen _Controller_ erhöht den verwendeten Speicher, aber er geht nie unter. (_Ich habe die WebApi-Vorlage verwendet_)

Hallo,

Ich habe das gleiche Problem mit ASP.NET Core 2. Ich habe ein Speicherabbild erstellt und versucht, es zu analysieren. Soweit ich sehe, ist das Problem genau so, wie der OP es gesagt hat. Meine Anwendung beginnt mit der Zuweisung von etwa 75 MB und geht sehr schnell bis zu ~ 750 MB, davon sind 608 MB "Nicht verwendeter Speicher, der .NET zugewiesen ist".

Erster Schnappschuss beim App-Start:
image

Zweiter Schnappschuss nach 3 Minuten und 100 Anfragen:
image

Wir stehen auch vor dem gleichen Problem, unser Controller verarbeitet große Datenmengen (was ein schlechtes Design ist und bald ersetzt wird). Jeder Aufruf dieses Controllers führt dazu, dass der Speicher wächst. Der Speicher reduziert sich aber nur um 40-50% (gewinnt 50 Mb, reduziert 30-35 Mb), jeder Aufruf erhöht den Speicher jedes Mal im Bereich von 10-15 Mb. Der Dienst wird innerhalb der Service-Fabric gehostet.

Es sieht so aus, als hätte ich ein ähnliches Problem in unserem Produktionsdienst (20-100 Anforderungen/s) mit einer Kombination aus:

  • ASP.NET Core 2.0.4
  • ServiceStack.Core 1.0.44
  • SkiaSharp 1.59.2
  • Docker v17.09.0-ce, Build afdb6d4 auf Ubuntu 16.04 x64
  • x4-Server mit 40 CPUs, 128 GB Arbeitsspeicher
  • Server-GC ist wahr
  • Jeder Docker-Container ist auf 12.000 (MHz) CPU-Anteile und 8 GB RAM eingestellt

Die Anwendung verfügt über einen Front-End-Webserver und einen Worker (jeweils in den folgenden Diagrammen dargestellt).

Webserver (letzte 6h)
screen shot 2018-01-13 at 1 06 24 pm

Arbeiter (letzte 6h)
screen shot 2018-01-13 at 1 07 55 pm

Beide verwenden große Byte-Arrays, da der Dienst als Objektspeicher-Proxy fungiert und folglich Objekte im LOH ablegt. Meine Frage ist, ist dies im Moment eine bekannte Einschränkung von .NET Core? Es scheint, als ob der LOH nie vollständig aufgeräumt oder fragmentiert wurde.

Allerdings scheint SOH gut zu funktionieren, da typische Web-API-Objekte bereinigt werden. Irgendwelche Vorschläge? Gibt es ein Problem mit meiner Einrichtung? Ich habe den Code analysiert und kann keine offensichtlichen Speicherlecks finden, und ich verwende nichts Besonderes außerhalb der ServiceStack-Bibliothek.

@sebastienros - irgendwelche Gedanken dazu? Haben wir ein ähnliches Verhalten in unseren Systemen beobachtet?

  • Wir messen dies nur auf 2.1, ich werde versuchen, dasselbe für 2.0 hinzuzufügen
  • Alle Kommentare scheinen sich auf die erwähnte LOH-Problematik zu beziehen, die bei der Anwendung berücksichtigt und möglichst große Arrays gepoolt werden sollten

@sebastienros , mehrere Fragen:

  1. Ich habe Ants Profiler verwendet, um die Speichernutzung zu messen, demnach wurde keine LOH-Fragmentierung festgestellt. Können Sie mir sagen, wie ich überprüfen kann, ob meine Anwendung unter LOH-Fragmentierungsproblemen leidet?
  2. Was sind die Ergebnisse für .net Core 2.1? Ist das Problem behoben, weil Kestrel Span verwendet??
  3. Was ist, wenn wir Arrays nicht in einem Pool zusammenfassen können – können Sie eine Problemumgehung bereitstellen? Sollten wir GCSettings.LargeObjectHeapCompactionMode.CompactOnce verwenden?

Was sind die Ergebnisse für .net Core 2.1? Wurde das Problem behoben, weil Kestrel Span verwendet?

Wir persönlich haben keine Beweise dafür gesehen, dass das Problem in Kestrel liegt. Es sieht immer noch nach einem Anwendungsproblem aus.

Was ist, wenn wir Arrays nicht in einem Pool zusammenfassen können – können Sie eine Problemumgehung bereitstellen? Sollten wir GCSettings.LargeObjectHeapCompactionMode.CompactOnce verwenden?

@jkotas @Maoni0 Irgendwelche Ratschläge hier?

Wie kann ich untersuchen, ob ich das gleiche Problem habe? Der LOH-Speicherprofiler von Redgate ist fast leer, wie @sinapis beschreibt, verwendet aber immer noch einfach mehr als 1 GB für nur einen Benutzer

Sammeln Sie Traces und analysieren Sie sie mit perfview. Es gibt eine Reihe von Tutorials von Vance und anderen zum Aufspüren von .NET-Speicherlecks: https://www.bing.com/search?q=.NET%20memory%20leak%20perfview .

https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/linux-performance-tracing.md enthält Linux-spezifische Anweisungen zum Sammeln von Ablaufverfolgungen.

Wenn Sie glauben, dass kein Speicherleck vorliegt und GC nur mehr Speicher bereithält, als Sie möchten, können Sie Folgendes versuchen:

  • Verwenden von Speicherbeschränkungen für Windows-Job-Objekte oder Docker-Container, um zu begrenzen, wie viel Speicher der Prozess verwenden kann. Der GC berücksichtigt diese Grenzen und läuft aggressiver, wenn er sich ihnen nähert.
  • Oder von Server GC zu Workstation GC wechseln. Es ist nicht ungewöhnlich, dass Server-GC einen viel höheren Spitzenarbeitssatz haben. Workstation hat einen niedrigeren höheren Spitzenarbeitssatz, aber auch einen geringeren Durchsatz.

Hallo,

Ich glaube, ich habe das gleiche Problem mit einer .Net Core-Web-API in der Produktion.

Die Anwendung läuft auf Windows Server 2016 mit .Net Core 2.0.3. Die Maschine ist eine Hyper-V-VM mit 28 CPU-Kernen und 24 GB RAM. Wenn wir den IIS-Anwendungspool nicht oft genug recyceln, werden wir schließlich den gesamten verfügbaren Speicher verwenden. Wenn die Anwendung beginnt, viel Speicher zu verwenden (>=95 % des gesamten Systemspeichers), steigt auch die CPU-Auslastung stark an (manchmal von 2 % auf 70 %). Ich bin mir nicht sicher, ob eine OOM-Ausnahme ausgelöst wird oder nicht, wir recyceln den Pool immer, bevor es passiert (die maximale Speichernutzung, die ich gesehen habe, war 98 % des von dotnet.exe verwendeten Speichers).

Bei der Analyse eines Produktionsspeicherauszugs mit ".Net Memory Porfiler" (SciTech Software) habe ich Folgendes gefunden:
image

Wenn diese Analyse richtig ist, befinden sich ca. 95 % des Speichers im „Overhead > ungenutzt“. So beschreibt dieser Speicherprofiler-Editor diese Kategorie (in seinem Forum):
_„Overhead->Unused“ ist Speicher, der von der .NET-Laufzeit für den verwalteten Heap festgeschrieben wird. Es wird derzeit nicht verwendet, steht jedoch für zukünftige Instanzzuweisungen zur Verfügung. Es gibt viele Regeln, die die Laufzeit verwendet, um zu entscheiden, ob der festgeschriebene Speicher behalten oder an das Betriebssystem freigegeben werden soll. Dies hängt von Faktoren wie dem verfügbaren Arbeitsspeicher, Zuweisungsmustern, der Anzahl der Prozessoren, der Verwendung des Server-GC usw. ab._

@jkotas Ich werde Ihre Empfehlungen anwenden (Windows-Job-Objekt und Wechsel zu Workstation GC) und Sie über das Ergebnis informieren. Bitte lassen Sie mich wissen, ob ich weitere nützliche Informationen aus den Produktionsspeicherauszügen extrahieren kann, die ich habe.

Danke

@sinapis @ronald7
Kann jemand von euch eine App teilen, die das Problem zeigt? Wenn ich es reproduzieren könnte, könnten wir den Grund finden oder zumindest Stück für Stück Code entfernen und eine minimale Repro isolieren.

@sebastienros Ich kann die App nicht freigeben, aber ich kann die Sitzung von PerfView session + memory dump freigeben.
Einige Beschreibung: Ich habe eine ASP.NET Core 2-Web-API, ich habe einen Lasttest mit 200 Benutzern erstellt, die alle dieselbe Anforderung über 10 Sekunden senden. Insgesamt wurden 775 Anfragen bearbeitet.

Diese App sprang im Task-Manager auf fast 1 GB Speicherverbrauch und blieb so. Wenn ich mir den Dump ansehe, kann ich ungefähr 18 MB zählen:

image

Die Frage ist also, wo ist fast 1 GB geblieben?

@sinapis Danke

Das von Ihnen beschriebene Verhalten ist nicht unerwartet, der GC wird bei Bedarf bei Spitzenlast etwas Speicher zuweisen und ihn im Laufe der Zeit einfach freigeben. Es ist der GC-Server-Modus, und warten Sie normalerweise auf Leerlaufzeiten, um ihn freizugeben und Ihre App-Leistung nicht zu beeinträchtigen. Die Speichermenge, die reserviert wird, hängt von dem gesamten auf dem System verfügbaren Speicher ab.

Wir würden definitiv ein Problem sehen, wenn es weiter zunehmen würde. Ich gehe davon aus, dass die Speichernutzung sinkt, wenn Sie keine Anfragen mehr senden und Ihre App ausführen lassen.

Könnten Sie dasselbe ausführen, bis es den größten Teil Ihres Systemspeichers verbraucht? Oder zumindest lange genug mit der gleichen Last, dass es zeigt, dass es kontinuierlich wächst? Ich werde mir trotzdem deine aktuellen Dumps ansehen.

Können Sie auch Dumps während und am Ende der Jobs erstellen, damit wir die Details sehen können.

Hallo @sebastienros

Leider kann ich weder die App noch die Speicherauszüge teilen, aber ich werde eine Dummy-Anwendung erstellen (mit derselben Architektur und denselben Abhängigkeiten), sie auf derselben Maschine ausführen, wenn ich dieses Verhalten reproduzieren kann, werde ich diese mit Ihnen teilen. Bitte lassen Sie mich wissen, ob es nützliche Informationen gibt, die ich für Sie aus den Speicherauszügen extrahieren kann.

Ich habe den GC-Modus von _server_ auf _workstation_ auf einem Produktionsserver aktualisiert. Ich werde Sie in ein paar Stunden darüber informieren, ob sich etwas an der Speichernutzung ändert.

Ich habe auch einen weiteren Test durchgeführt: Wir führen unsere Anwendung hinter einem Load Balancer auf 4 virtuellen Maschinen aus. Nachdem eine der Maschinen aus dem Load-Balancer-Pool entfernt wurde, verringerte sich der von dotnet.exe verwendete Arbeitsspeicher nicht und blieb auch nach 30 Minuten auf dem gleichen Niveau. (Die Anwendung verarbeitete jedoch immer noch einige Anfragen: alle 30 Sekunden eine von SCOM an einen Dummy-Endpunkt gesendete Anfrage). Es wurde kein Speicher freigegeben und an das System zurückgegeben.

Danke

@sinapis Ich habe mir Ihren ETW-Trace angesehen. Es ist mir ein Rätsel - Sie haben in der letzten induzierten Gen2-GC nur sehr wenig überlebt, aber wir haben uns trotzdem dafür entschieden, so viel Speicher festzuhalten. Ihre Anwendung scheint ein Randfall zu sein (Sie haben aufgrund von LOH-Zuweisungen meistens nur Hintergrund-GCs durchgeführt) - Ich frage mich, ob wir dort einige Abrechnungsfehler haben (eine andere Möglichkeit sind Fehler in den gemeldeten Zahlen, aber wenn Sie bereits überprüft haben, dass Sie so viel zugesagt haben, ist das a kleinere Möglichkeit). wenn Sie etwas reproduzieren könnten, das Sie mit mir teilen könnten, wäre das fantastisch; andernfalls, wenn es möglich ist, Ihre App mit etwas Protokollierung von GC auszuführen (ich kann Ihnen einen Commit geben, der das tut), wäre das auch hilfreich.

@Maoni0 teilen Sie bitte mit, wie ich die GC-Protokollierung aktivieren soll
Wenn Sie möchten, dass ich andere Daten zur Verfügung stelle, um den Buchhaltungsfehler zu widerlegen, teilen Sie mir bitte mit, was ich Ihnen zur Verfügung stellen soll und wie (vielleicht perfview sagen, dass es weitere Daten sammeln soll?).
Ich werde versuchen, eine minimale Repro zu erstellen, bin mir aber nicht sicher, ob ich Erfolg haben werde, da ich nicht weiß, wo das Problem liegt.

@sebastienros hoffentlich werde ich heute einen weiteren Dump mit mehr Speicherverbrauch liefern

Hallo @sebastienros @Maoni0 ,

Ich habe unsere Anwendung 12 Stunden lang im Workstation-GC-Modus ausgeführt, aber das gleiche Ergebnis. Ich habe die Anwendung auch mit .Net 2.1 Preview 2 auf einem einzelnen Produktionsknoten für 1 Stunde neu kompiliert, ich werde Sie über das Ergebnis informieren, aber im Moment verwendet der Prozess bereits mehr als 2 GB RAM.

image

Ich habe PerfView auf demselben Computer ausgeführt und sammle GC-Dumps. Gibt es eine E-Mail-Adresse, an die ich Ihnen den OneDrive-Link senden könnte, leider kann ich ihn nicht direkt in diesem Thread teilen.

Wenn es helfen kann, kann ich auch weitere Metriken oder GC-Protokolle sammeln. Danke

@ronald7 _redigiert_ Ich kann an @Maoni0 weiterleiten

Hallo @sebastienros @Maoni0 Ich habe dir gerade eine E-Mail mit zwei PerfView gcdump und einer VMMap-Datei geschickt, ich hoffe, das kann helfen. Auf meiner Seite versuche ich immer noch, dieses hohe Speicherverbrauchsverhalten mit einer Dummy-Anwendung zu reproduzieren.

Danke!

Ich habe auch das gleiche Problem. Die Garbage Collection findet nie statt! Der Screenshot zeigt die Speichernutzung nach etwa 50 Anfragen mit einer ziemlich einfachen dotnet-Core-Web-API-App.

memory-profile2

Ich habe gerade eine ASP.NET Core-App, die auf Ubuntu 16.04 ausgeführt wird, von 1.1 auf 2.0 aktualisiert und bin auf dieses Problem gestoßen. Es ist ziemlich schwerwiegend und führt dazu, dass der Kernel die App aufgrund von OOM-Fehlern häufig beendet, und ich überlege, ob ich auf 1.x zurückstufen soll. Es gibt bestimmte Seiten, die wir überhaupt nicht laden können - selbst nach einem Kestrel-Neustart erschöpft die App den verfügbaren Speicher sofort nach einer einzigen Anfrage! Ich habe über ein Upgrade des Servers nachgedacht, aber basierend auf den Kommentaren hier zu ASP.NET Core-Apps, die den gesamten verfügbaren Speicher verwenden, hoffe ich nicht, dass dies helfen wird. Unser Stack ist im Grunde ASP.NET MVC Core + EF Core ... nichts Besonderes. Wenn ich etwas Zeit habe, werde ich versuchen, ein Beispiel zu erstellen, um das Problem zu reproduzieren - ich denke nicht, dass es angesichts der Einfachheit unseres Stacks so schwierig sein sollte.

FWIW, das System, das ich aktualisiert habe, hat auch eine .NET Core-Konsolen-App, und die scheint nach dem 2.0-Upgrade keine Speicherprobleme zu haben, also scheint dies definitiv ein ASP.NET Core-bezogenes Problem zu sein.

@danports haben Sie versucht, GC.Collect() aufzurufen, um zu sehen, ob die Speichernutzung dramatisch sinkt? das würde uns einen Anhaltspunkt geben, wo wir anfangen sollten. Wenn GC.Collect() (oder die GC.Collect/GC.WaitingForPendingFinalizers/GC.Collect-Sequenz) nicht in der Lage ist, die Speichernutzung drastisch zu senken, bedeutet dies, dass einfach so viel Speicher aktiv sein muss, damit GC ihn nicht zurückfordern kann.

@Maoni0 Das habe ich noch nicht ausprobiert. Ich glaube nicht, dass mein Problem mit GC zusammenhängt, da ich von Zeit zu Zeit einen Rückgang der Speicherauslastung festgestellt habe – es scheint nur so, als ob meine .NET Core 2.0-Apps ungefähr das 2-3-fache des Speichers verbrauchen, den sie im Vergleich zu ihrer Ausführung auf .NET Core 2.0 hatten. NET-Core 1.1. 😞

Ich habe vorerst ein Downgrade auf .NET Core 1.1 durchgeführt und werde später darauf zurückkommen, wenn ich mehr Zeit habe, wahrscheinlich nach der Veröffentlichung von .NET Core 2.1. (Ich bin mit 2.0 auf einen Haufen Probleme gestoßen, und dies war nur eines davon.)

GC.Collect() hilft nicht. Versuchte eine sehr einfache ASP.NET Core 2.0- und 2.1-Web-API mit einem Controller, der ein Wörterbuch mit 200.000 Ganzzahlen zurückgibt. Der zugewiesene Speicher steigt mit jeder Anfrage, obwohl die App keinen weiteren Speicher verwendet.

@Serjster , das 200.000 Ganzzahlen (4B) zurückgibt, würde 800 KB benötigen. In diesem Fall treffen Sie auf das Problem, das in diesem Kommentar erläutert wird: https://github.com/aspnet/Home/issues/1976#issuecomment -289336916

In diesem Fall sollten Sie einen Array-Pool verwenden, um sie über Anforderungen hinweg wiederzuverwenden.

Gut zu wissen ist auch, dass, wenn Code im 64-Bit-Modus ausgeführt wird, Arrays/Listen usw., die Zeiger enthalten, im Vergleich zu 32-Bit doppelt so groß sind. Wenn ich mich richtig erinnere, führt das vollständige Framework standardmäßig jeden 32-Bit-CPU-Code in 64-Bit-Betriebssystemen aus. Leute, die ihren Code migrieren, könnten also versehentlich auf LOH-Probleme stoßen.

Ich arbeite mit @Serjster und hier ist, was ich gefunden habe. Wenn ich ein Vanilla-Web-API-Projekt mit asp.net Core erstelle (ich habe 2.1 in meinem letzten Test verwendet), stelle ich fest, dass beim Ausführen des Diagnosetools (oder sogar beim Überprüfen des im Code festgelegten Prozessarbeitsspeichers) die Anzahl der Bytes zurückgegeben wird steigt weiter, wenn ich einen Endpunkt erreiche. Zum Beispiel, wenn ich einen einzelnen Web-API-Endpunkt habe, der ein Wörterbuch zurückgibtbei 20.000 Artikeln passiert folgendes:

  1. Beim ersten Besuch der Controller-Methode beträgt der Prozessspeicher 83 MB.
  2. Ich warte ein paar Sekunden, und beim zweiten Besuch wird es auf 86 MB verschoben.
  3. Ich warte ein paar Sekunden und der dritte Besuch wechselt auf 90 MB.
  4. Wieder - 94 MB.
  5. Ich mache das n-mal und es erreicht schließlich etwa 304 MB. Sobald es dies tut, pendelt es sich ein.

Wenn das zurückgegebene Objekt ein Objekt mit einer anderen Größe ist, sind alle obigen Zahlen nur größer/kleiner (einschließlich des Ausgleichsbetrags), aber das Wachstumsmuster ist dasselbe (auch bekannt als es wächst und wächst, bis es sich nach vielen Anfragen einpendelt). .

Wenn ich GC.Collect im Methodenaufruf hinzufüge (also bei jeder einzelnen Anfrage auftritt), ist das Niveau von viel niedriger, aber es gibt immer noch eine Wachstumsphase, bis es sich einpendelt.

Der andere interessante Detailpunkt ist die Anzahl der Objekte und die Haufengröße beim Erstellen von Schnappschüssen bleibt bei jedem Besuch weitgehend unverändert. Aber das Process Memory-Diagramm zeigt eine immer höhere Zahl (dies gilt auch, wenn Sie den Prozess greifen und den Arbeitsspeicher-Sollwert ziehen).

Ich fange an zu vermuten, dass das Diagramm zugewiesenen Speicher anzeigt (und dieser Speicher wächst basierend auf einer asp.net-Kernnutzungs-/Nachfrageprognoselogik), aber dies ist nicht unbedingt verbrauchter/durchgesickerter Speicher. Ich weiß jedoch nicht genug, um das zu bestätigen, also frage ich mich, ob jemand, der sich besser auskennt, sich melden kann.

BEARBEITEN - re @davidfowl Kommentar: In Bezug auf Ihren Kommentar zu Dingen, die selten gesammelt werden ... könnte dies Sinn machen. Aber wie lange dauert es normalerweise? Ich kann zwischen Anfragen mehr als 30 Sekunden vergehen, und der GC scheint diese Speichernummer im Diagnosediagramm nie wieder herunterzusetzen. Ich bin mir sicher, dass ich hier etwas unwissend bin, aber ich bin nur neugierig.

BEARBEITEN 2 - Jetzt, wo ich den SO-Link gelesen habe, den David oben gepostet hat, fange ich an zu glauben, dass dies definitiv das Problem ist, das wir sehen. Wenn wir in einer Umgebung mit begrenztem Speicher laufen (was wir in unserer Entwicklungsumgebung tun, wo wir das sehen, weil wir billig sind), stoßen wir auf Probleme damit.

Bearbeiten 3 - Eine verbleibende Frage. Warum steigt der Prozessspeicher ständig, aber die Heap-Größe steigt nicht, wenn dies ein LOH-Problem ist? Eigentlich kann ich das jetzt verstehen. Der Heap ist der verwendete Speicher. Der dem Prozessor zugewiesene Speicher ist der verwendete Speicher plus die fragmentierten Speicherblöcke, die nicht verwendet werden.

@RemyArmstro kannst du Dictionary<int, int> in SortedDictionary<int, int> ändern? Das Wörterbuch weist wahrscheinlich kontinuierlichen Speicher zu, fügt möglicherweise sogar zusätzliche Daten zu jedem Eintrag hinzu. So wie SortedDictionary implementiert ist, werden viele kleine Zuweisungen statt einer großen vorgenommen.

Bearbeiten: Wenn Sie in Zeichenfolgen und nicht direkt in den Antwortausgabestream serialisieren, kann dies auch zu LOH-Zuweisungen führen.

@wanton7 Ihre Antwort verfehlt den Punkt. Wörterbuch ist nur die Spitze des Eisburgs. Wir können Listen, Arrays usw. usw. verwenden, und sie alle tun dasselbe. Wie jedoch darauf hingewiesen wurde, wenn der LOH dies verursacht, wie es sich anhört, ist dieses Verhalten wahrscheinlich in Ordnung? Abgesehen davon, dass dies einige besorgniserregende Nebenwirkungen haben könnte, z. B. was passiert, wenn Ihnen der Speicher ausgeht? Stürzt Ihre App einfach ab?

@Serjster ok Ich dachte, Sie hätten nur kleine Fälle, in denen dies passiert. Für mich ist es sehr ungewöhnlich, große Listen, Arrays wie diese zu haben und so viele Daten in einem API-Aufruf zu senden, wenn es nicht binär ist. Wenn Sie eine Art Web-API haben und Daten daraus abrufen, verwenden Sie normalerweise Paging. Sie sollten nicht 10000 Einträge an die Clientseite senden.
Aber wenn Sie viele solche Probleme haben und es keine Möglichkeit gibt, die Funktionsweise Ihrer API zu ändern, sollten Sie meiner Meinung nach Ihre eigenen Chunked List- und Dictionary-Implementierungen erstellen. Wenn Sie wirklich so große Arrays verwenden, können Sie sie durch Ihre aufgeteilten Listen ersetzen oder versuchen, sie beim Start der Anwendung zu bündeln.

Ich wünschte, Microsoft würde Chunked-Implementierungen erstellen, die jeder in solchen Situationen verwenden könnte.

@wanton7 Wieder einmal verfehlst du den Punkt. Die Größe der Liste spielt keine Rolle. Sogar ein einzelnes Element oder eine kleine Liste verursacht dieses Problem.

@Serjster vielleicht bin ich nur blind, aber ich sehe keine Beiträge von Ihnen, in denen Sie sagten, dass das Senden eines einzelnen Elements oder einer kleinen Liste dies verursachen wird. Hast du es gelöscht?

Oder von @RemyArmstro Er spricht von unterschiedlich großen Wörterbüchern. Ich habe Corefx überprüft und Dictionary wird Array oder diese zuweisen

private struct Entry
{
  public int hashCode;    // Lower 31 bits of hash code, -1 if unused
  public int next;        // Index of next entry, -1 if last
  public TKey key;           // Key of entry
  public TValue value;         // Value of entry
}

Eine 85000-Byte-Zuweisung verursacht eine LOH-Zuweisung, sodass ein Wörterbuch mit einer Kapazität von 5313 Einträgen von int-Schlüsseln und int-Werten eine LOH-Zuweisung verursacht. Die Kapazität ist nicht dasselbe wie die Zahl oder die Einträge, die Kapazität scheint durch Primzahlen erweitert zu werden, überprüfen Sie die private Resize-Methode des privaten Wörterbuchs. Jede Struktur könnte eine zusätzliche Zuweisung plus Speicherauffüllung haben, sodass sogar niedrigere Einträge eine LOH-Zuweisung verursachen könnten.

Details zur Wörterbuchimplementierung Dictionary.cs

Edit: feste URL

@wanton7 Danke. Ich denke, wir erkennen jetzt, worum es geht. Es ist nur schade, dass es dafür keine großartige + einfache Lösung gibt. Es kommt im Grunde darauf an, sich dessen bewusster zu sein und anzupassen, wie Sie Code schreiben. Der Nachteil ist, dass sich dieser nicht verwaltete Speicher etwas verwalteter anfühlt. :( Letztendlich haben wir vielleicht nur wenige Bereiche, die diese Zuweisungsgrenze wirklich überschreiten, aber einer der Bereiche ist ziemlich zentral für unsere App, also sehen wir ihn derzeit häufig. Ich denke, wir müssen diesen Teil nur überdenken, überwachen und versuchen, alle anderen Bereiche aufzuspüren, in denen wir dieses Kriechen bemerken. Nochmals vielen Dank!

Wir haben tatsächlich bald eine ähnliche Situation und müssen eine chunked IList<T> Implementierung erstellen. Ich werde eine gewisse Größe für Chunks verwenden, die bitshiftfähig sind, sodass ich einfach Bitshift und Maske zum Indizieren verwenden kann.

Ich würde gerne wissen, was für GC vorteilhafter ist, größerer Chunk oder kleinerer Chunk? Ab Größen zwischen 1KB und 64KB. Kleinere Chunks bedeuten mehr Referenzen für GC, aber ich würde vermuten, dass größere Chunks für die Komprimierung und Fragmentierung schlechter sind.

Ihr Verständnis ist genau richtig - ich würde mit nicht zu großen Größen gehen; Probiere es wahrscheinlich mal mit 4k/8k.

@ Maoni0 danke!

Ich habe mich für 4KB entschieden, damit wir keine bösen Überraschungen erleben, falls wir unseren Code mal unter Mono laufen lassen. Durch Lesen von http://www.mono-project.com/docs/advanced/garbage-collector/sgen/working-with-sgen/ herausgefunden, dass die LOH-Schwelle unter Mono nur 8000 Bytes beträgt.

Gibt es Fortschritte bei diesem Problem?

Wir beobachten dasselbe Problem, bei dem der Prozessspeicher weiter wächst, obwohl die Heap-Größe gleich bleibt (oder abnimmt).

@sebastienros kannst du dir das nochmal anschauen? Vielleicht können wir einige detaillierte Anweisungen bereitstellen, um den Leuten zu helfen, ihre Szenarien weiter zu untersuchen?

Hier sind einige Punkte, die in unserer Situation zu berücksichtigen sind:

  • Wir geben nur ein Dictionary<int, int> -Objekt mit 1000 gespeicherten Integer-Werten zurück. Nichts weiter als das.
  • Wir haben unser Projekt von .NET Core 2.0 --> 2.1 konvertiert
  • Wir sehen dieses Problem in MS Visual Studio 2017

Codieren Sie wie folgt:

    public async Task<IActionResult> SampleAction()
    {
        var list = new Dictionary<int, int>();
        for (int n = 0; n < 1000; n++) list.Add(n, n);
        return Ok(list);
    }

Zur Reproduktion müssen Sie irgendeine Form von mäßiger Belastung simulieren. Wir haben gerade mit Postman schnell geklickt und konnten dieses Verhalten beobachten. Nachdem wir die Lastsimulation beendet hatten, beobachteten wir, wie die Heap-Größe abnahm, der Prozessspeicher jedoch gleich blieb (selbst wenn wir GC erzwangen).

Ich sehe dies auch in einem meiner Projekte, aber ich kann es auch in einer brandneuen .net-Core-API neu erstellen, die auf .Net Core 2.1 (SDK 2.1.302) abzielt.

Ich habe das Beispiel-API-Projekt angehängt, das ich mit Visual Studio 15.8.0 Preview 4 erstellt habe. Um zu zeigen, wie der Arbeitsspeicher zunimmt, habe ich eine .net-Core-Konsolen-App alle halbe Sekunde auf den GET-Endpunkt der Standardwerte gesetzt, um die beiden Zeichenfolgen abzurufen. Die Prozessspeicherauslastung ist langsam, aber in einem Projekt, das mehr Daten zurückgibt, kann dies schnell ansteigen.

screenshot
WebApplication1.zip

Ich habe diesen Beitrag auf Stack Exchange gefunden:

https://stackoverflow.com/questions/48301031/why-doesnt-garbage-collector-in-net-core-2-0-free-all-memory

Hat jemand seine Anwendungen im Freigabemodus profiliert, um zu sehen, ob dieses Verhalten vorhanden ist? Ich werde das heute mal ausprobieren und schauen, ob das Problem weiterhin besteht.

Bearbeiten : Ich habe versucht, im Release-Modus zu profilieren, und das Problem besteht weiterhin. Ich erzwinge sogar eine GC, um zu sehen, ob das Auswirkungen hat.

image

@chrisaliotta danke für den Link zu diesem Beitrag, ich war mir dieses Verhaltens nicht bewusst. Es wäre in der Tat interessant zu sehen, ob das erklärt, was die Leute sehen.

@Eilon @chrisaliotta Danke, aber das hat nichts mit dieser Diskussion zu tun. Dass .NET im Debug-Modus keinen Speicher freigibt, ist ein bekanntes Verhalten, und deshalb messen wir den Speicherverbrauch (und potenzielle Lecks) nur im Release-Modus. Auch im Release-Modus werden Sie aufgrund des Server-GC-Modus feststellen, dass der Arbeitsspeicher im Laufe der Zeit in gewissem Maße ansteigt. Dieses Beispiel beweist also aus zwei verschiedenen Gründen nichts.

@sebastienros Stimmt das Verhalten, das @beef3333 und ich beobachten, mit dem überein, was zu erwarten ist? Wo nämlich private Bytes trotz abnehmender Heap-Größe erhöht bleiben? Wenn dies der Fall ist, erscheint es mir seltsam, dass jede inkrementelle Anforderung weiterhin dazu führt, dass die privaten Bytes wachsen, obwohl freier Heap-Speicher vorhanden ist.

Im Debug-Modus ja. Versuchen Sie also bitte, den Release-Modus zu verwenden, und führen Sie Ihren Stress für eine lange Zeit aus. Wenn der Speicher unbegrenzt anwächst, liegt ein Speicherleck vor. Wenn der Speicher recycelt wird (selbst wenn er eine beträchtliche Menge an Speicher benötigt), ist in Ihrem Fall alles in Ordnung.

Ich habe es gerade noch einmal mit demselben Projekt getestet, das ich im Release-Modus angehängt habe, und ich sehe genau das gleiche Verhalten.

Ich werde Ihre Anwendung dann testen, danke.

Ich habe die von @beef3333 bereitgestellte Anwendung 2 Stunden lang lokal mit einer Rate von 5.000 RPS ausgeführt, und der Speicher ist stabil (Varianz um 1 MB insgesamt, bei 400 MB auf einem Computer mit 32 GB). Der GC wird regelmäßig korrekt aufgerufen. Ich habe auch mehrere Dumps im Laufe der Zeit überprüft und die verschiedenen Instanzen werden wie erwartet erstellt und gesammelt. Ich verwende 2.1.1.

@sebastienros Vielen Dank, dass Sie sich darum gekümmert haben. Ich denke, das Wesentliche an all dem ist:

  • Die Speicherverwaltung verhält sich für eine .NET Core-Webanwendung anders als für Ihre 08/15-Desktopanwendung.
  • Entwickler sollten sich auf den durchschnittlichen Speicherverbrauch als Funktionsanfragen pro Sekunde (RPS) über einen bestimmten Zeitraum konzentrieren.
  • Das Wachstum privater Bytes weist möglicherweise nicht immer auf Speicherlecks hin.

Korrigieren Sie mich, wenn ich falsch liege, aber es scheint, dass .NET Core den zugewiesenen Speicher basierend auf durchschnittlichen Anforderungen erhöht, um die schnellste Reaktionszeit zu gewährleisten? Wenn dies zutrifft, kann man davon ausgehen, dass dieser zugewiesene Speicher wahrscheinlich nicht freigegeben wird, bis der Anwendungspool zurückgesetzt wird – oder wird er diesen zugewiesenen Speicher im Laufe der Zeit freigeben, wenn RPS abnimmt?

Gleicher Fehler.
Ich habe einen asp.net-Webapi-Backend-Dienst.
Die Stacks sind asp.net mvc, autofac, automapper, castle.dynamicproxy, Entity Framework Core.
Der gesamte Speicher wird verbraucht, dann stürzt der Dienst ab.

Version ist 2.1.0

@atpyk Update auf 2.1.1. Wenn das nicht hilft, sollten Sie wirklich profilieren, was diese Erinnerung bewahrt. Ich habe https://www.jetbrains.com/dotmemory/ verwendet, aber es gibt wahrscheinlich auch andere Tools, die dies tun können. Es kann anzeigen, was tatsächlich im Large Object Heap (LOH) zugewiesen ist.

Läuft du im 32bit Modus? Da Large Object Heap-Zuweisungen (größer als ~85000 Byte) aufgrund von Fragmentierung zu Speicherausnahmen im 32-Bit-Modus führen können. Mit Dictionary können Sie diese Grenze sehr leicht überschreiten. Überprüfen Sie diesen Kommentar https://github.com/aspnet/Home/issues/1976#issuecomment -393833505

Wenn Sie Ihren Code im vollständigen .Net Framework ausführen, wird standardmäßig jeder CPU-Code im 32-Bit-Modus ausgeführt. Sie müssen 32-Bit bevorzugen in den Projekteinstellungen deaktivieren oder einige Registrierungseinstellungen in der Registrierung Ihres Servers standardmäßig auf 64-Bit setzen.

@wanton7 Vielen Dank. Ich werde deine Lösungen ausprobieren.

Ich habe auf 2.1.2 aktualisiert und auf Microsoft Azure-Webapp mit win-x64 bereitgestellt, aber keine Wirkung. @wanton7
dotnetcorememory

@atpyk bitte erstellen Sie einen Speicher-Snapshot (dump_ und analysieren Sie ihn (Visual Studio, MemoScope), um zu sehen, welches Objekt den gesamten Speicher beansprucht oder nur an Zahl zunimmt. Sie können auch zwei nehmen und sie im Laufe der Zeit vergleichen.

@sabastienros Ich glaube, dass genug Leute diesbezüglich Bedenken geäußert haben, dass Sie / MS tatsächlich anfangen sollten, dies selbst zu analysieren. Vielleicht funktioniert das so, wie Sie es beabsichtigt haben, aber dann ist das Design fehlerhaft.

Unseren Apps geht irgendwann der Arbeitsspeicher aus und sie stürzen ab, und das alles in einer Azure-Produktionsumgebung. Das ist nicht akzeptabel.

@atpyk dann klingt es nach einem Speicherleck. Profilieren Sie Ihr Gedächtnis, um zu sehen, was dieses Gedächtnis bewahrt, wie @sebastienros sagte.

Eine Frage, verwenden Sie überhaupt ASP.NET Core? Ich habe Ihren ersten Kommentar erneut gelesen und Sie erwähnen ASP.NET MVC. ASP.NET MVC und ASP.NET Core sind zwei völlig unterschiedliche Produkte. Diese Probleme und dieses Repo für ASP..NET Core.

Bearbeiten: Nur die Versionsnummern klingen so, als würden Sie ASP.NET Core verwenden, wollten aber sichergehen.

Wir verwenden .net Core MVC. @wanton7
Ich analysiere die Erinnerung. Möglicherweise führt der Castle Dynamic Proxy zu einem Speicherleck.
memroy1
memroy2
memroy3
dynamicproxy

@Serjster laufen Ihre Programme in 32-Bit .NET Core und stürzen mit Ausnahmen wegen Speichermangels ab? Wenn Ihr Code viele LOH-Zuweisungen vornimmt, ist die Speicherfragmentierung wahrscheinlich der Grund.
Wenn Sie in einer 32-Bit-Umgebung arbeiten, haben Sie zwei Möglichkeiten: Korrigieren Sie Ihren Code, um LOH zu vermeiden, oder wechseln Sie zur 64-Bit-Umgebung.

Ich bin mit Azure nicht sehr vertraut, habe aber nach ein wenig Googeln diese https://blogs.msdn.microsoft.com/webdev/2018/01/09/64-bit-asp-net-core-on-azure-app gefunden

@Serjster Ich glaube, dass nicht alle Berichte hier gleich sind, und ziehe es vor, die Gültigkeit jedes einzelnen Falls zu überprüfen. Etwas wie „Meine App hat ein Speicherleck“ bedeutet nicht, dass es am Framework liegt, also ziehe ich es vor, sicherzustellen, dass es sich in jedem Fall um ein tatsächliches handelt.

Nehmen wir zum Beispiel Ihren Fall: "Ich glaube", dass ich den Grund beantwortet habe, warum Ihr Gedächtnis zunimmt. Konntest du es nach meiner Erklärung beheben? Oder es hat das Problem nicht gelöst und können Sie in diesem Fall eine Anwendung geben, die ich lokal ausführen kann, um das Problem zu reproduzieren?

@sebastienros Was wir am Ende herausfanden, war, dass die Speicherzuweisung immer weiter zunahm, obwohl der Speicherverbrauch dies nicht tat. Ich weiß, dass der ASP.NET-Kern einige Heuristiken durchführt, um ihm mitzuteilen, dass er mehr greifen sollte, aber es schien bei jeder Anfrage ständig mehr und mehr zuzuweisen. Es erscheint mir in dieser Hinsicht fast zu gierig, aber ich könnte mich irren.

Wie auch immer, ich denke @Serjster Punkt ist, dass dieser Thread weiter wächst, weil hier eindeutig einige Verwirrung herrscht. Im alten ASP.NET-Land (vor Core 1, glaube ich) mussten wir dieses Verhalten nicht sehen (zumindest nicht in diesem Ausmaß. Es ist vielleicht nicht wirklich ein Fehler/Problem, aber es ist definitiv etwas, das viele Leute verursacht immer wieder die gleiche Frage stellen.

Es wäre schön, wenn es einen offiziellen Artikel gäbe, der diesen Thread wirklich von oben nach unten behandelt, anstatt sich wie bisher im Kreis zu drehen. Hoffe das hilft zur Klärung.

Es wäre schön, wenn es einen offiziellen Artikel gäbe, der diesen Thread wirklich von oben nach unten behandelt, anstatt sich wie bisher im Kreis zu drehen. Hoffe das hilft zur Klärung.

Ich stimme dem zu. Es wäre gut für uns zu wissen, warum .NET Core 2.1 in Bezug auf die Speicherverwaltung „opportunistischer“ ist als frühere Versionen.

@sebastienros können wir hier bitte eine Zusammenfassung der Probleme haben? es gibt 81 Kommentare - ich habe den Eindruck, dass es nicht nur um die Probleme geht (obwohl ich sie überhaupt nicht sorgfältig gelesen habe, also könnte ich mich irren). Wenn ja, können wir alle unterschiedlichen Probleme hier auflisten und sehen, ob wir Repros für jedes von ihnen haben? Es gibt genug Leute, die die Gedächtnissteigerung erwähnt haben. Ich denke, es rechtfertigt uns, Repros zu bekommen und herauszufinden, ob dies allgemeine Probleme sind oder nicht.

Sicher. Ich versuche derzeit, alle diese Threads zu identifizieren und zu sehen, wie der Status für jeden von ihnen ist. Ich werde dieses Thema irgendwann schließen und spezifischere wieder eröffnen, die sich auf jeden Bericht konzentrieren, da dieser einzelne Thread nicht mehr nachhaltig ist. Ich werde sie hier für diejenigen in diesem Thread verlinken, die ihnen folgen möchten.

Parallel werde ich an einem Dokument arbeiten, das alle Empfehlungen, die bekannten Speicherprobleme (LOB, HttpClient, ...) und die Möglichkeiten zur Analyse und Meldung dieser Probleme auflistet.

Nur um Ihnen zu versichern, dass wir uns um dieses Problem kümmern und um Speicherlecks präventiv zu erkennen, haben wir in den letzten 6 Monaten eine ASP.NET-Anwendung kontinuierlich auf Azure ausgeführt, sowohl unter Linux als auch unter Windows, für 24 Stunden und 7 Tage. Diese Tests rufen bei jeder Iteration (täglich oder wöchentlich) die neueste ASP.NET-Quelle ab. Wir messen RPS, Latenz, CPU- und Speicherauslastung. Die Anwendung verwendet EF Core, MVC und Razor und wird bis zu 50 % der CPU aufrechterhalten, um eine erhebliche Last zu simulieren.

Sie können die Ergebnisse öffentlich hier auf dieser Seite sehen (durchsuchen Sie den Tagesbericht zu finden): https://msit.powerbi.com/view?r=eyJrIjoiYTZjMTk3YjEtMzQ3Yi00NTI5LTg5ZDItNmUyMGRlOTkwMGRlIiwidCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0NyIsImMiOjV9&pageName=ReportSectioneeff188c61c9c6e3a798

Dadurch konnten wir in der Vergangenheit einige Probleme beheben und uns darauf verlassen, dass es derzeit keine grundlegenden Lecks im System gibt. Aber es ist noch lange nicht möglich, alle von uns gelieferten Komponenten zu verwenden, und es könnten Probleme auftreten, die wir identifizieren müssen. Die Bereitstellung von Dumps und Anwendungen, die die Probleme reproduzieren, sind die wichtigsten Möglichkeiten, wie Sie uns helfen können.

@sebastienros Vielen Dank für die Updates. Ich weiß, dass es in unserem Fall eher um ein neues Problem der "gierigen Speicherzuweisung" ging, das wir ursprünglich als Speicherleck verwechselt haben. Ich bin mir nicht einmal sicher, ob es jetzt ein Problem gibt, es könnte nur sein, dass die neuen Optimierungsheuristiken viel aggressiver sind. Ich bin mir nicht sicher ... aber ich denke, Sie sind auf dem richtigen Weg, diesen Thread wirklich zu bewerten und einige konsolidierte Erklärungen / Zusammenfassungen darüber zu finden, was die Leute sehen / missverstehen. Viel Glück!

Alle einzelnen Meldungen wurden isoliert und werden einzeln nachverfolgt und geschlossen, wenn sie bereits gelöst sind. Fühlen Sie sich frei, diese zu abonnieren, um auf dem Laufenden zu bleiben.

Parallel werde ich an einem Dokument arbeiten, das alle Empfehlungen, die bekannten Speicherprobleme (LOB, HttpClient, ...) und die Möglichkeiten zur Analyse und Meldung dieser Probleme auflistet.

Dies ist ein riesiges +1 von mir. Ich denke, dass eines der größten Probleme hier darin besteht, wie schwierig es sich anfühlt, Informationen zu sammeln, um dann zu versuchen, zu bestimmen, _was_ das Problem ist. Einige großartige Dokumente zu haben, die es uns ermöglichen, einige Anweisungen zu befolgen, um (i) zu sammeln, (ii) eine Selbstdiagnose zu versuchen und (iii) unsere Dumps/Ergebnisse auf eine Weise zu veröffentlichen, die für das MS-Team effizient ist, kann beiden wirklich helfen Seiten des Zauns.

Wenn wir (die Entwickler) besser in der Lage sind, Diagnosen zu stellen und/oder Informationen bereitzustellen, dann ist dies eine Win-Win-Situation für alle.

Nochmals vielen Dank fürs Zuhören @sebastienros - sehr geschätzt, Kumpel!

Was denkst du über die Situation auf dem Bild unten?

Wir führen 4 WebApps innerhalb desselben Plans aus. Anfangs war es B1, skaliert auf S2 und der Speicher wuchs weiter, bis ich auf die hungrige Webapp csproj umstellte:

<ServerGarbageCollection>false</ServerGarbageCollection>

und deaktivieren Sie auch Application Insights

  1. Ich glaube, da der Speicher mit der obigen Einstellung unter Kontrolle gehalten werden konnte, gibt es keine Speicherlücke. Richtig?
  2. Ist das dargestellte Verhalten normal?

memory eaten up

Dieselbe Situation hier wie bei @alexiordan , wir hatten eine .net Core 2.1-Konsole, auf der einige in Kube gehostete IHostedServices ausgeführt wurden, FROM microsoft/ dotnet:2.1-runtime AS base. Wir wollten HealthChecks aktivieren, also haben wir asp.net nur mit der HealthChecks-Middleware hinzugefügt und das Basisimage in microsoft/ dotnet:2.1-aspnetcore-runtime geändert. Das Ergebnis war OOM. Wir haben es geschafft, die Speicherallokation durch Hinzufügen zu stabilisierenfalsch im csproj.

Unsere Analyse hat gezeigt, dass in einer asp.net-App der GC weniger häufig sammelt und auch die Finalizer-Warteschlange seltener durchlaufen wird.

Wenn wir den GC dazu zwingen, die Finalizer-Warteschlange zu sammeln und zu durchlaufen, indem wir Folgendes in unsere Pipeline einfügen:

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();

die Speicherbelegung blieb stabil.

Was denkst du über die Situation auf dem Bild unten?

Wir führen 4 WebApps innerhalb desselben Plans aus. Anfangs war es B1, skaliert auf S2 und der Speicher wuchs weiter, bis ich auf die hungrige Webapp csproj umstellte:

<ServerGarbageCollection>false</ServerGarbageCollection>

und deaktivieren Sie auch Application Insights

  1. Ich glaube, da der Speicher mit der obigen Einstellung unter Kontrolle gehalten werden konnte, gibt es keine Speicherlücke. Richtig?
  2. Ist das dargestellte Verhalten normal?

memory eaten up

Hallo @alexiordan

Wir sehen ein sehr ähnliches Speicherprofil auch bei der Verwendung von KI (Web-App auf Net Core 2.1). Sind Sie bei der Lösung dieses Problems weiter fortgeschritten? Natürlich wollen wir KI in den Apps belassen.

Es ist seltsam, dass die Nutzung mit jeder Anfrage zunimmt, aber das Festlegen des obigen Werts auf "false" scheint es für mich zu stoppen? seltsam, weil Sie denken würden, dass der Wert wahr wäre, der es ermöglicht, aber es scheint umgekehrt zu sein ...

Ich habe vergessen zu erwähnen, dass ich es kurz nach der Ankündigung meiner Absicht, einen Artikel über die in diesem Thread beschriebenen Probleme zu schreiben, tatsächlich getan habe. Sie können es hier sehen: https://github.com/sebastienros/memoryleak

Es wird mit einer kleinen Anwendung geliefert, die die Muster live in einem Diagramm darstellt.

aber das Festlegen des Obigen auf "false" scheint es für mich zu stoppen? seltsam, weil Sie denken würden, dass der Wert wahr wäre, der es ermöglicht, aber es scheint umgekehrt zu sein ...

Die Client-Garbage-Collection (optimiert für die gemeinsame Nutzung von Arbeitsspeicher mit vielen Apps und das Freihalten von Arbeitsspeicher) ist aggressiver als die Server-Garbage-Collection (optimiert für Durchsatz und Parallelität).

Wenn ich SGC auf „false“ setzte, fiel meine asp.net-Kern-API von 150 MB auf 48 MB und wuchs danach nicht mehr bei jeder Anfrage. Ist dies also in Wirklichkeit vorerst die beste Einstellung für die Produktion?

@kgrosvenor eigentlich kommt es drauf an. Zitat aus dem ausgezeichneten Artikel von @sebastienros :

In einer typischen Webserverumgebung ist die CPU-Ressource kritischer als der Arbeitsspeicher, daher ist die Verwendung des Server-GC besser geeignet. Einige Serverszenarien sind jedoch möglicherweise besser für einen Workstation-GC geeignet, beispielsweise auf einer hochdichten Hostingplattform für mehrere Webanwendungen, bei der Arbeitsspeicher zu einer knappen Ressource wird.

Vielen Dank, das ist sehr praktisch, ich werde daran denken - werde diesem Thread für weitere Updates folgen, wobei ich gesagt habe, dass ich den asp.net-Kern absolut liebe :)

Leiden Sie auch darunter mit einer .net Core 2.1-Konsolen-App. ständiges Gedächtniswachstum. habe Docker-Container auf ein niedriges Maximum gesetzt, damit es darauf trifft und neu startet, was in Ordnung funktioniert, aber es ist hässlich.

Irgendwelche Neuigkeiten auf dieser Seite? Das gleiche Verhalten haben wir auch in ASP.Net Core v2.1. Von dem, was ich im Commit https://github.com/aspnet/AspNetCore/commit/659fa967a1900653f7a82f02624c7c7995a3b786 sehen kann, scheint es ein Speicherverwaltungsproblem zu geben, das in v3.0 behoben wird?

@flo8 hast du versucht, auf 2.2 zu aktualisieren und das Verhalten überprüft? https://dotnet.microsoft.com/download

Wenn Sie die neueste Version 2.2 ausführen und auch dieses Problem haben - das bloße Erstellen einer Liste von 1 Million Ints und das Zurückgeben eines emptyResult() erhöht meinen Heap um einige hundert MB bei jeder Anforderung, bis mir der Speicher ausgeht. Das Setzen von ServerGarbageCollection auf false hat es geheilt, obwohl es nicht wie die richtige Lösung zu sein scheint ...

@dre99gsx Da es scheint, dass Sie eine einfache Repro haben, könnten Sie ein Projekt und Schritte teilen, damit ich dasselbe lokal tun kann?

In diesem Fall sollte es das LOB füllen, aber sie sollten auf gen2 gesammelt werden. Bitte teilen Sie auch mit, in welcher Umgebung ich dies reproduzieren kann, Betriebssystem, Speicher, Last.

Sorry für die kryptische Antwort. Ziemlich leicht:
(Windows 7 64bit, 16 GB RAM, Google Chrome für HTTP-Anfragen, VS2017-Community) - Ich gewöhne mich immer noch daran, diesen Threads Code hinzuzufügen, entschuldigen Sie das Aussehen.

  • Starten Sie eine neue .NET Core 2.2-Web-App
  • Injizieren Sie eine Dienstklasse mit Bereich (nichts Besonderes ...) in den Controller-Konstruktor
  • Lassen Sie die Aktion Index() des Controllers eine Methode dieser Serviceklasse aufrufen
  • Erstellen Sie eine Modellklasse (DumbClass) mit einer Eigenschaft: public int ID {get; einstellen;}
  • Instanziieren Sie in der Dienstklassenmethode eine Liste und füllen Sie sie:
    var lst = neue Liste();
    für (i=0; i<10000000; i++) <--- Hinweis: 10 Millionen Iterationen
    {
    lst.add (neue DumbClass () {ID = i});
    }
  • Rückkehr von der Methode, müssen nichts zurückgeben, aber Sie können diese Liste auch zurückgeben ...
  • index() gibt neues EmptyResult() zurück;

Rufen Sie jetzt einfach alle 8 Sekunden die Aktion auf und beobachten Sie, wie der Profiler-Speicher steigt. Auf meinem System sehe ich Folgendes auf Private Bytes:

Anwendung starten: 155 MB
1. HTTP-Get-Anfrage: 809 MB
2.: 1,2 GB
3.: 1,4 GB
4.: 1,8 GB
5.: 2,1 GB ... 2,3 GB ... 2,6 GB ...

Nun, irgendwann scheint GC einzugreifen, aber in diesem Beispiel fällt es nie unter 3 GB. Wie bereits erwähnt, wenn ich den ServerGC auf false stelle, steigt er nie über 1 GB, obwohl er immer noch dort hochklettert und bei 1 GB schwebt.

Lassen Sie mich wissen, ob das hilft und ob Sie es reproduzieren können. Oh, ich habe Ihren Github-Beitrag gelesen: „Memory Management and Patterns in ASP.NET Core“, fantastischer Bericht, danke für Ihren Beitrag!

@dre99gsx 👋

Ich gewöhne mich immer noch daran, diesen Threads Code hinzuzufügen, entschuldigen Sie das Aussehen.)

Überhaupt keine Probleme :) Frage: Könnten Sie tatsächlich die gesamte Beispielanwendung auf GitHub (kostenlose Repos) oder an einen ähnlichen Ort stellen? Das ist der einfachste Weg für alle anderen, schnell _die gesamte_ exakte Beispiel-App/Repo, mit der Sie gespielt haben, zu klonen/herunterzuladen.

Auch Screenshots der Speichernutzung mit TaskManager würden helfen (wenn unter Windows - oder das Äquivalent auf * nix .. was der Befehl top ist ??)

Toller Einsatz bisher!

/me kehrt dazu zurück, diesen Thread stillschweigend ernsthaft zu beobachten.

Zur Erinnerung: https://github.com/sebastienros/memoryleak : Hier finden Sie einige Demos und Erklärungen für alle Symptome, die im Thread beschrieben werden

Außerdem wurde jedes dieser Probleme einzeln behandelt, und keiner hat sich __bisher__ als Fehler im dotnet-Kern erwiesen, sondern als erwartetes Verhalten.

@dre99gsx Nun zurück zum letzten Kommentar, ich möchte Sie dringend bitten, ein separates Problem von diesem Thread einzureichen. Als ich auf meinem Handy war, wusste ich nicht, dass es "dieser" war ;). Aus Ihrem ersten Kommentar sagen Sie

bis mir der Speicher ausgeht

Ich würde also eine OutOfMemory-Ausnahme erwarten, weshalb ich um eine Repro gebeten habe. Aber in Ihrem nächsten Kommentar sagen Sie:

Nun, irgendwann scheint GC einzugreifen, aber in diesem Beispiel fällt es nie unter 3 GB

Es gibt also kein Speicherproblem. Dies ist typisch für eine Maschine mit vielen Kernen und viel verfügbarem Speicher. Der GC gibt die verwalteten Heaps frei, der Speicher wird jedoch weiterhin festgeschrieben, da es keinen Grund gibt, die Festschreibung aufzuheben (viel verfügbarer Speicher). Dies ist ein Standardverhalten in .NET, und ich demonstriere es in dem Artikel, auf den ich verwiesen habe. Sie können dies auch lesen: https://blogs.msdn.microsoft.com/maoni/2018/11/16/running-with-server-gc-in-a-small-container-scenario-part-0/

Ich weiß, dass das Runtime-Team derzeit an Möglichkeiten arbeitet, .NET-Anwendungen, die in Containern ausgeführt werden, einzuschränken, damit sie nicht so viel Arbeitsspeicher verwenden und auf 3.0 abzielen, um einige Microservice-Szenarien zu lösen.

Und wie Sie selbst herausgefunden haben, sollten Sie den Workstation-GC-Modus verwenden, wenn Ihre Anwendung nicht den gesamten verfügbaren Speicher auf dem Server verwenden kann.

Richtig, als ich sagte "kein Speicher mehr", stütze ich mich darauf, dass ich visuell keinen verfügbaren Speicher für eine andere Anwendung über Windows Private Working Set (Task-Manager) sehe; keine "Out of Memory Exception".

Weißt du was, du hast recht. Dies sieht mehr und mehr wie das erwartete Verhalten aus, und wenn so viel Speicher verfügbar ist, warum Ressourcen dafür aufwenden, ihn freizugeben, wenn ihn sonst niemand benötigt! Ich verstehe es. Solange GC schlau genug ist, Speicher freizugeben, damit andere Anwendungen nicht eingeschränkt werden, werde ich es einfach so lassen, wie es ist, und es sein Ding machen lassen. Danke noch einmal!

Ich habe meine Anwendung in Asp.net Core 2.2 entwickelt und stehe auch vor dem gleichen Problem im Zusammenhang mit der Speicherfreigabe.
jeder Aufruf erhöht den Speicher im Bereich von 40-50 MB, jedes Mal, wenn keine Freigabe erfolgt.

Ich habe auch das erwähnte Tag ServerGarbageCollection>false hinzugefügt
immer noch das gleiche Problem für 50 Benutzer, es verwendet ca. 2 GB RAM im In-Process- Modus (w3wp iis worker process)

Bitte helfen Sie.

Bitte helft!! das gleiche Problem wie ankitmori14

@ankitmori14 , @ikourfaln – wenn Sie den Kommentar von @sebastienros unter https://github.com/aspnet/AspNetCore/issues/1976#issuecomment -449675298 gelesen haben und immer noch glauben, dass ein Speicherproblem vorliegt, reichen Sie bitte ein neues Problem ein mit detaillierten Schritten zum Reproduzieren des Problems sowie alle anderen Informationen und Spuren, die Sie über das Verhalten haben. Bitte denken Sie daran, dass es unwahrscheinlich (aber nicht unmöglich) ist, dass ein Fehler vorliegt, es sei denn, die App/der Prozess weist tatsächlich Fehler auf. Der standardmäßige 'Server' Garbage Collector versucht nicht, so wenig Speicher wie möglich zu verwenden; es tritt eher ein, wenn es nötig ist, z. B. wenn der Speicher tatsächlich zur Neige geht. Selbst eine kleine App kann also 2 GB Speicher verbrauchen, und das ist kein Problem, da noch 4 GB frei sind.

Hallo,

Wir haben dieses Problem: https://stackoverflow.com/questions/53868561/dotnet-core-2-1-hoarding-memory-in-linux

Grundsätzlich wächst der Speicher über die Tage im Prozess, bis Kubernetes ihn tötet, weil er das konfigurierte Limit von 512 MB erreicht. Komischerweise ging der Speicher beim Erstellen eines Speicherauszugs drastisch zurück, ohne dass der Prozess neu gestartet wurde oder so. Bei der Untersuchung des Speicherauszugs sahen wir viele Objekte ohne Root.

Wir haben gestern auch die gleichzeitige GC (dh Hintergrund-GC) deaktiviert und es scheint jetzt besser zu sein, aber wir müssen mindestens eine Woche warten, um dies zu bestätigen.

<PropertyGroup>
  <ServerGarbageCollection>false</ServerGarbageCollection>
  <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>
</PropertyGroup>

@vtortola Frage, als Sie das 512-MB-Limit für Ihre Anwendung konfiguriert haben, hatten Sie eine Vorstellung von der Anzahl der gleichzeitigen Anforderungen, die Sie verarbeiten wollten, oder haben Sie getestet, wie viele gleichzeitige Anforderungen Ihre App verarbeiten kann, bevor sie umfällt?

Wir haben einige vorläufige und grobe Tests durchgeführt und überprüft, ob wir 500 gleichzeitige Websockets pro Pod mit 512 MB verarbeiten können. Wir liefen stundenlang mit 2 Pods und 1000 gleichzeitigen Verbindungen mit einem Speicher von weniger als 150 MB. Die bereitgestellte Anwendung mit 2 Pods hat zu jedem Zeitpunkt zwischen 150 und 300 gleichzeitige Verbindungen, und der Arbeitsspeicher variiert von weniger als 100 MB in den ersten Tagen bis zum Erreichen von 512 MB in etwa 2 Wochen. Es scheint keine Korrelation zwischen der Anzahl der Verbindungen und dem verwendeten Speicher zu geben. Mehr als 70 % der Verbindungen dauern 10 Minuten.

Könnten Sie einen Speicherauszug teilen, wenn er bei 100 MB und 512 MB liegt, um zu sehen, welche Instanzen noch am Leben sind?

Ich fürchte, ich kann einen Dump nicht teilen, da er Cookies, Tokens und viele private Daten enthält.

Kannst du das dann vor Ort vergleichen? In Bezug darauf, welches Objekt den meisten Speicher benötigt und ob ihre Anzahl nicht mit Ihrer Last korreliert. Wenn Sie beispielsweise 300 Verbindungen haben, sollten keine 3K-Verbindungsobjekte vorhanden sein.

Leider hat der Test der Einstellung von <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection> nicht geholfen und der Prozess hortet immer noch Speicher.

Wir haben einen Linux-Dump des Prozesses, das einzige Tool, das wir haben, um ihn zu analysieren, ist lldb, und wir sind in dieser Angelegenheit sehr unerfahren.

Hier ein paar Daten falls es mal klingelt:

(lldb) eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00007F8481C8D0B0
generation 1 starts at 0x00007F8481C7E820
generation 2 starts at 0x00007F852A1D7000
ephemeral segment allocation context: none
         segment             begin         allocated              size
00007F852A1D6000  00007F852A1D7000  00007F853A1D5E90  0xfffee90(268430992)
00007F84807D0000  00007F84807D1000  00007F8482278000  0x1aa7000(27947008)
Large object heap starts at 0x00007F853A1D7000
         segment             begin         allocated              size
00007F853A1D6000  00007F853A1D7000  00007F853A7C60F8  0x5ef0f8(6222072)
Total Size:              Size: 0x12094f88 (302600072) bytes.
------------------------------
GC Heap Size:            Size: 0x12094f88 (302600072) bytes.

Und das Ergebnis von dumpheap -stat : https://pastebin.com/ERN7LZ0n

Wie Grafana den Speicherstatus gemeldet hat, finden Sie unter https://stackoverflow.com/questions/53868561/dotnet-core-2-1-hoarding-memory-in-linux

Wir haben eine weitere Reihe von Diensten im dotnet-Kern, die einwandfrei funktionieren, obwohl sie keine Websockets verwenden.

@vtortola würde es dir etwas ausmachen, ein neues Problem zu erstellen, damit wir dieses nicht forken. Ich denke, die Tatsache, dass es WebSockets verwendet, macht es einzigartig, und wir müssen mindestens eine Beispiel-App erstellen, die sich wie Ihre verhält und sie über einen langen Zeitraum belastet. Können Sie beschreiben, was Ihre Kunden mit dem Websocket machen, wie sie sich damit verbinden und wie lange? Ich könnte eine App wie diese einrichten und über Tage ausführen und Speicherabbilder erstellen, wenn ich sehe, dass der Speicher wächst.

Es könnte auch ein Konflikt zwischen dem GC und Kubernetes vorliegen, sodass der GC nicht gewarnt wird, dass er nahe an der Grenze des Pods ist.

@richlander arbeitet an einem ähnlichen Problem. Rich, könnte dieser Fall (lesen Sie nur die letzten 6 Kommentare) mit dem zusammenhängen, woran Sie arbeiten?

Wenn es einen Unterschied macht, habe ich das gleiche (oder ein sehr ähnliches) Problem. Ich habe mehr als ein Dutzend .net Core 2.1- und 2.2-Konsolen-Apps, die auf Docker ausgeführt werden - jeder Container mit einem Speicherlimit von 512 MB, der auch Websockets (Client) verwendet, und die Apps erreichen das Container-Speicherlimit alle ~3 Tage. Der Container wird dann heruntergefahren und neu gestartet.

Alles verwendet authentifizierte Dienste, daher kann ich nicht bereitstellen, was ich habe, aber ich kann möglicherweise etwas zusammenstellen, das eine Testsite verwendet, um das Problem zu reproduzieren.

Welche Parameter verwenden Sie, um die Speichergrenzen festzulegen? Nur --memory oder auch --memory-swap ?

Wenn ich es teste, kann ich sehen, dass es sehr gut berücksichtigt wird und nie das von mir festgelegte Limit überschreitet, selbst bei einem super niedrigen Limit wie 16 MiB, aber es wechselt wie verrückt auf der Festplatte. Und ich teste mit einer App, die DB-Abfragen (EF) und Razor-Ansichten rendert.

@sebastienros absolut, ich habe https://github.com/aspnet/AspNetCore/issues/6803 erstellt

Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.

Ich habe derzeit Speicherprobleme.

Nach einer Stunde in der Produktion wird der gesamte Arbeitsspeicher vom w3wp.exe-Prozess (der .NET Core InProcess ausführt) verwendet. Das Ändern des GC auf Workstation hat bei mir nicht funktioniert.

Nach der Analyse eines Speicherauszugs fand ich dieses ähnliche Problem, https://github.com/aspnet/AspNetCore/issues/6102.

Ich hoffe, es später heute in der Produktion testen zu können, nachdem ich auf die neueste .NET Core-Laufzeit aktualisiert habe, derzeit 2.2.3. Ich lasse Sie wissen, wie es geht.

Ich habe ähnliche Probleme mit der Speichernutzung. Wenn ich meinen Linux-Containern Grenzen setze, macht es OOM nur schneller. Dies geschieht sogar mit den grundlegenden Vorlagen in Visual Studio. Eines habe ich festgestellt - Core 2.1 und 2.2 sind betroffen. Core 2.0 ist nicht - aber es ist EOL :(

Siehe oben

Ich weiß, dass das Runtime-Team derzeit an Möglichkeiten arbeitet, .NET-Anwendungen, die in Containern ausgeführt werden, einzuschränken, damit sie nicht so viel Arbeitsspeicher verwenden und auf 3.0 abzielen, um einige Microservice-Szenarien zu lösen.

Und wie Sie selbst herausgefunden haben, sollten Sie den Workstation-GC-Modus verwenden, wenn Ihre Anwendung nicht den gesamten verfügbaren Speicher auf dem Server verwenden kann.

Leider hilft der Workstation-Modus überhaupt nicht - leider bin ich nicht wirklich in der Lage, eine der 3.0-Vorschauen oder ähnliches auszuprobieren.

@PrefabPanda stellen Sie sicher, dass Sie tatsächlich im Workstation-GC-Modus ausgeführt werden, indem Sie überprüfen, ob System.Runtime.GCSettings.IsServerGC gleich false ist.

Dann könnte dies ein echtes Speicherleck sein. Öffnen Sie ein separates Problem, vielleicht der beste Schritt.

@wanton7 - danke, ich habe es noch einmal überprüft und das ist definitiv eingestellt.

@DAllanCarr - wird reichen

Ich bin mir fast sicher, dass es kein Speicherleck ist. Eher wie Docker-Einstellungen werden möglicherweise nicht richtig erzwungen und der GC tritt nicht ein, bevor das Limit erreicht ist. Ich weiß, dass 3.0 Korrekturen in diesem Sinne einführt.

@richlander sieht dieses Problem nach etwas aus, von dem bekannt ist, dass es in 2.2 nicht funktioniert?

@PrefabPanda würde es Ihnen etwas ausmachen, die genaue Docker-Version, die Sie verwenden, und die Docker-Compose-Datei zu teilen? Ich versuche zu reproduzieren, aber zwischen Docker- und Docker-Compose-Versionen fällt es mir schwer, dieses Problem lokal zu replizieren.

@sebastienros , @richlander – Danke, dass du dich bei mir gemeldet hast. Ich schätze es sehr.

Meine Docker-Versionen:

Docker Desktop-Community
Version 2.0.0.2 (30215)

Motor: 18.09.1
Verfassen: 1.23.2

Siehe beigefügt das gesamte Testprojekt:
WebApplication1.zip

teste curl-Requests.zip

Für alle Fälle mein Dockerfile:

VON mcr.microsoft.com/dotnet/core/ aspnet:2.2 AS base
ARBEITSVERZ /app
AUSSETZEN 80
AUSSETZEN 443

VON mcr.microsoft.com/dotnet/core/sdk:2.2 AS-Build
ARBEITSVERZ /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
Führen Sie die dotnet-Wiederherstellung „WebApplication1/WebApplication1.csproj“ aus.
KOPIEREN . .
ARBEITSVERZ "/src/WebApplication1"
FÜHREN Sie dotnet build „WebApplication1.csproj“ -c Release -o /app aus

VON build AS veröffentlichen
FÜHREN Sie dotnet publish „WebApplication1.csproj“ -c Release -o /app aus

VON der Basis AS endgültig
ARBEITSVERZ /app
COPY --from=publish /app .
EINSTIEGSPUNKT ["dotnet", "WebApplication1.dll"]

docker-compose.yml:

Version: '2.4'

Dienstleistungen:
Webapplikation1:
Bild: ${DOCKER_REGISTRY-}webapplication1
mem_reservation: 128m
mem_limit: 256m
memswap_limit: 256m
Prozessor: 1
bauen:
Kontext: .
Dockerdatei: WebApplication1/Dockerfile

docker-compose-override.yml:

Version: '2.4'

Dienstleistungen:
Webapplikation1:
Umgebung:
- ASPNETCORE_ENVIRONMENT=Entwicklung
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_HTTPS_PORT=44329
- DOTNET_RUNNING_IN_CONTAINER=true
- DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true
- ASPNETCORE_preventHostingStartup=true
Häfen:
- "50996:80"
- "44329:443"
Volumen:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/ https:ro
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/us ersecrets:ro

@sebastienros - selbst wenn es eine Möglichkeit gibt, eine separate Umgebungsvariable in den Container einzufügen, die der GC betrachten kann, würde das für mich gut funktionieren.

Ich habe versucht, es explizit aufzurufen, aber es hilft nicht - ich nehme an, selbst wenn es im Code aufgerufen wird, sieht es immer noch die falsche Speichergröße des Containers/Computers.

@PrefabPanda , als Sie sagten "Ich habe versucht, es explizit anzurufen", könnten Sie bitte erläutern, was genau bedeutet? GC sieht das korrekte Container-Speicherlimit, wenn Sie eines angegeben haben, unabhängig davon, ob es auf natürliche Weise oder induziert ausgelöst wird. Wenn Sie GC.Collect() aufgerufen haben, wird eine vollständige Blockierungssammlung durchgeführt. und wenn Sie GC.Collect(2, GCCollectionMode.Default, true, true) ausführen, wird eine vollständige Komprimierung von GC durchgeführt, wenn dies zurückgibt, dass der Heap die kleinstmögliche Größe hat, unabhängig vom Containerlimit oder irgendetwas anderem.

Hallo @Maoni0 - Ich habe GC.Collect (2, GCCollectionMode.Default, true, true) ausprobiert

Ich habe gerade einen anderen Kommentar gesehen, der besagt, dass 256 MB zu klein für 2.2 sind, aber möglicherweise in 3.0 "behoben" werden. Sieht so aus, als müsste ich noch etwas experimentieren...

Wenn Sie GC.Collect(2, GCCollectionMode.Default, true, true) ausprobiert haben und der Speicher nicht wie erwartet ausgefallen ist, bedeutet dies, dass Sie ein echtes Speicherleck haben. Sie sind sich nicht sicher, wie viele Tools in Ihrer Umgebung verfügbar sind. kannst du überhaupt sos befehle ausführen? Wenn ja, können Sie immer nachsehen, was nach Ihrer induzierten GC auf dem Haufen verbleibt

Danke @Maoni0 - denken Sie daran, dass ich eine Vorlage in Visual Studio verwende - es gibt buchstäblich keinen eigenen Code in diesem Testprojekt, das ich angehängt habe. Ich habe ein anderes Feedback, das ich bearbeiten muss, ich werde mich mit Ihnen in Verbindung setzen. Danke vielmals.

@Maoni0 - Ich habe versucht, das höhere Limit einzustellen, kein Unterschied. Sieht so aus, als müsste ich die 3.0-Vorschau ausprobieren

Ich möchte die Kommentare zu diesem Thema sperren, da es sich um ein sehr altes handelt, bei dem alle Fälle in separaten Ausgaben behandelt wurden. Ich habe dies aus Versehen kommentiert, weil ich dachte, ich hätte https://github.com/aspnet/AspNetCore/issues/10200 kommentiert

Danke

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen