.NET Garbagecollector-Problem. Blöcke für 15-40 Minuten

8

Einige Fakten: Wir haben den WCF-Dienst entwickelt, der als Schicht zwischen den Clients und der Datenbank fungiert. Es ist Selfhosted und läuft als Windows-Service.

Der Dienst hält mehrere Caches, wobei die größten etwa 1-2 GB im Speicher sind. Die Gesamtspeicherbelegung beträgt normalerweise 5-8 GB. Verbindungen sind Duplex und verwendet TCP-Protokoll und die Serialisierung erfolgt mit Protobuf-Net. Die Anzahl unserer verbundenen Kunden reicht normalerweise von 1000 bis 1500. Der Server ist ein 8-Core-Xeon von neuartigem Modell mit 64 GB Arbeitsspeicher und läuft nicht mehr als der Service.

Das Problem: Nach x Zeit ist es überall von einem Tag bis zu einer Woche der Service extrem langsam geworden. Anfragen, die 0,5 Sekunden dauern, können eine Minute dauern. Dieses Verhalten dauert 15 bis 40 Minuten oder bis der Dienst neu gestartet wird.

Was wir getan haben: Wir haben die Netzwerk- und Netzwerkverbindung zum Server überprüft und es gibt kein Problem. Die CPU-Auslastung steigt während dieser Zeit etwas von f.eks. 30% durchschnittlich bis 40-50% durchschnittlich Wir haben Speicherauszüge erstellt und es gibt keine logischen Sperren im Code, die die Benutzer blockieren und überhaupt nicht viel Aktivität. Unsere neueste Führung ist der Müllsammler. In perfmon können wir sehen, dass "% time in gc" konstant über 90% ist, (90-97%) und die Anzahl der Aufrufe steigt. Beide GC0 und GC1. Wir vermuten, dass es auch einen blockierenden GC2 gibt, aber wir mussten den Dienst neu starten, da dieser in Produktion ist, so dass er während des 5min Fensters, in dem wir ausgeführt wurden, nicht hochging. Die Speicherbelegung betrug 7,6 GB. Hinweis: Ausstehende Anrufe steigen, so dass die Anrufe dort ankommen, aber der Dienst nicht damit umgehen kann.

Meine Fragen sind: Kann der Müllsammler in einen Zustand kommen, in dem er ständig läuft und für über 15 Minuten blockiert? Oder hängt das Problem wahrscheinlich mit einem anderen Problem zusammen?

Unser Dienst hat GC im Workstation-Modus und im Latenzmodus ausgeführt: Interaktiv Wir haben dies nun zu Server und SustainedLowLatency geändert und hoffen, dass dies etwas helfen wird. Gibt es noch etwas, was wir tun können, wenn es der Müllsammler ist?

Bearbeiten: Die große Speichernutzung ist von Entwurf, die Daten in den Caches sind so groß und es ist viel mehr Speicher verfügbar.

    
Johan Lindberg 04.03.2015, 08:48
quelle

2 Antworten

4

Eine übermäßige Speicherbereinigung wird häufig durch Code-Probleme verursacht. Sie erstellen entweder zu viele Objekte in kurzer Zeit, oder Sie reservieren Speicher, ohne ihn freizugeben.

Es gibt tatsächlich eine umfangreiche Checkliste, die auf MSDN verfügbar ist das sollte Ihnen helfen, das Problem zu diagnostizieren.

Ein sehr großer GC2 bedeutet, dass die darin enthaltenen Objekte mehrere Speicherbereinigungen überstanden haben, was bedeutet, dass sie für eine längere Zeit im Speicher gehalten werden. Das könnte die Ursache Ihres Problems sein. Vielleicht gibt es einen Caching-Mechanismus, der eine Optimierungs- / Aufbewahrungsrichtlinie verwenden könnte (Entfernen von Daten, die lange nicht verwendet wurden).

    
Patrick Hofman 04.03.2015 08:55
quelle
0

Ich habe eine ähnliche Situation. Großer Datenbankdatencache in einem Dienst, der den Protobuf mit WCF für die Clientkommunikation verwendet. Der Cache ist nicht nur für Clients gedacht, die Business-Schicht verwendet den Cache, um Operationen auszuführen. Der Speicherbedarf des Dienstes kann zwischen 2 und 10 GB liegen. Ich gebe nach 8 Stunden Inaktivität einen Teil des Caches frei. Die Maschine verfügt über 8 virtuelle Kerne und 32 GB Speicher. Ich verwende .Net 4.5.1.

Der GC würde 98% der CPU für eine Stunde verbrauchen, sobald ich den Cache von der Datenbank geladen habe. Der interessante Punkt hier in beiden Fällen gibt es keinen Erinnerungsdruck was auch immer.

Ich denke, der GC wird unabhängig davon ausgeführt, dass etwas geändert wurde, wo der GC versucht, den verfügbaren Speicher für alle Threads zu behalten. Da ein Thread beim Laden des Caches eine große Menge an Speicher zugewiesen hat, trat der GC ein. Ich musste mehrere Dinge tun, um das Problem zu beheben.

1) Tupel aus dem Cache entfernt. Ich benutzte sie als Wörterbuchschlüssel und ihre Implementierung von StructuralEquality ist schrecklich. Es vergleicht alle Eigenschaften als Objekte, also gibt es eine Menge Boxen für Eigenschaften, die Werte sind und diese müssen zu irgendeinem Zeitpunkt Müll gesammelt werden.

2) Beim Ersetzen von Tupeln, die als Schlüssel verwendet wurden, konnte ich sie nicht einfach durch Strukturen ersetzen, ohne Equals zu implementieren, da der Wertvergleich Reflektionen verwendet und es zu teuer ist. Ich entschied mich dafür, Strukturen zu verwenden, um die Anzahl der Objekte zu entfernen, wenn sie in Arrays waren.

3) Um die Tupel zu entfernen, musste ich meine eigene Pair-Struktur erstellen, die die Eigenschaften mit den Standard-Equals für Eigenschaftstypen vergleicht. Im Wesentlichen das gleiche, was PowerCollections erstellt hat.

    
Edwin Unger 29.01.2016 15:58
quelle

Tags und Links