2010-06-22 19 views
12

Ausführen einer .NET-Anwendung unter Windows Server 2008 x64 mit 16 GB RAM. Diese Anwendung muss eine sehr große Datenmenge (etwa 64 GB) abrufen und analysieren und sie alle gleichzeitig im Speicher behalten..NET Garbage Collector und x64 virtueller Speicher

Was ich zu sehen erwarte: Die Prozessgröße wird von 16 GB auf 64 GB erweitert. Windows verwendet virtuellen Speicher, um die zusätzlichen Daten je nach Bedarf auf die/von der Festplatte zu übertragen. Dies ist der klassische Anwendungsfall für virtuellen Speicher.

Was ich tatsächlich sehe: Die Prozessgröße ist auf die Größe des physischen Speichers (16 GB) begrenzt. Die Anwendung verbringt 99,8% ihrer Zeit im Garbage Collector.

Warum verwendet unsere Anwendung keinen virtuellen Speicher? Ist dies ein Problem bei der Konfiguration des .NET-Garbage Collectors oder im virtuellen Windows x64-Speichermanager selbst? Was kann ich tun, damit unsere Anwendung virtuellen Speicher verwendet und nicht auf physischen Speicher beschränkt ist?

Danke.

- Brian

Update: Ich habe ein sehr kleines Programm geschrieben, das das gleiche Verhalten zeigt:

using System; 

namespace GCTest 
{ 
    class Program 
    { 
     static void Main() 
     { 
      byte[][] arrays = new byte[100000000][]; 
      for (int i = 0; i < arrays.Length; ++i) 
      { 
       arrays[i] = new byte[320]; 
       if (i % 100000 == 0) 
       { 
        Console.WriteLine("{0} arrays allocated", i); 
        System.Threading.Thread.Sleep(100); 
       } 
      } 
     } 
    } 
} 

Wenn Sie wollen, es versuchen, stellen Sie sicher, für x64 zu bauen. Möglicherweise müssen Sie die Konstanten etwas ändern, um Ihr System zu belasten. Das Verhalten, das ich sehe, ist, dass der Prozess abstürzt, wenn er sich einer Größe von 16 GB nähert. Es wird keine Fehlermeldung oder Ausnahme ausgelöst. Der Leistungsmonitor meldet, dass sich der Prozentsatz der CPU-Zeit in GC 100% nähert.

Ist das nicht inakzeptabel? Wo ist das virtuelle Speichersystem?

+0

Was verwenden Sie, um die Größe des Prozesses zu bestimmen? (Lassen Sie uns zuerst die einfachen Optionen beseitigen :)) – Paolo

+0

"Commit Größe" vom Windows Task-Manager. Außerdem verwenden Sie "# Gesamtzahl festgeschriebene Bytes" im Systemmonitor. Ich bin mir ziemlich sicher, dass ich die Größe des virtuellen Speichers des Prozesses und nicht seine physische Arbeitsmenge messe. – brianberns

+0

Kann ich das Offensichtliche fragen? Müssen Sie _really_ alle auf einmal in den Speicher laden? Ist es möglich, einen anderen Ansatz zu wählen und eine Art manuelles Paging durchzuführen? – CodingGorilla

Antwort

2

Es klingt, als ob Sie keinen Bezug zu den großen Daten haben. Der Garbage Collector wird keine referenzierten Objekte sammeln.

+0

Ich glaube nicht, dass das relevant ist. Keine der Daten ist eigentlich Müll - es ist alles referenziert. Daher erwarte ich nicht, dass der GC irgendwelche Speicher sammelt. Es scheint, dass der GC 100% der CPU verbraucht, da der physische Speicher des Prozesses aufgebraucht ist und .NET versucht, einige zu befreien.Es gibt jedoch nichts zu befreien - im Idealfall sollte der Prozess nur mit virtuellem Speicher erweitert werden, anstatt die gesamte Zeit im GC zu verbringen, um (nicht vorhandene) ungenutzte Objekte zu befreien. – brianberns

+0

Wenn Sie 64 GB Daten zuweisen, aber nur 16 GB tatsächlich zugewiesen sind, wird der Rest nicht referenziert und wurde GC'ed. Es sei denn, ich verstehe deine Frage nicht. –

+0

Sie verstehen die Frage nicht. Ich versuche, 64 GB Daten zu reservieren, aber der Prozess geht nach unten, nachdem ich nur 16 GB Daten zugewiesen habe. Ich bekomme nie eine Chance, den Rest der Daten zuzuordnen. – brianberns

10

Haben Sie überprüft, ob Ihre Auslagerungsdatei so konfiguriert ist, dass sie auf diese Größe erweitert werden kann?

aktualisiert

ich damit ziemlich viel mit dem gegebenen Beispiel herum habe zu spielen, und hier ist das, was ich sehe.

System: Windows 7 64bit, 6 GB Dreikanal-RAM, 8 Kerne.

  1. Sie benötigen eine zusätzliche Auslagerungsdatei auf einer anderen Spindel von Ihrem Betriebssystem oder diese Art von Untersuchung schlaucht Ihre Maschine. Wenn sich alles um die selbe Auslagerungsdatei streitet, wird alles noch schlimmer.

  2. Ich sehe eine große Menge an Daten, die von Generation zu Generation im GC befördert werden, sowie eine große Anzahl von GC-Sweeps \ Collections und eine massive Anzahl von Seitenfehlern als Folge der erreichten physischen Speichergrenzen. Ich kann nur annehmen, dass, wenn der physische Speicher erschöpft ist, dies Generations-Sweeps und Promotions auslöst, wodurch eine große Menge an ausgelagertem Speicher berührt wird, die zu einem Todesstoß führt, wenn berührte Speicher und andere Speicher ausgelagert werden ist herausgedrängt. Das Ganze endet in einem feuchten Durcheinander. Dies scheint unvermeidbar zu sein, wenn eine große Anzahl von langlebigen Objekten zugewiesen wird, die in dem Small Object Heap enden.

Nun ist diese vergleichen Objekte in einer Art und Weise zu Zuteilung wird sie direkt in das Large Object Heap zuweisen (die nicht die gleichen Fegen und Förderung Themen nicht leiden):

private static void Main() 
{ 
    const int MaxNodeCount = 100000000; 
    const int LargeObjectSize = (85 * 1000); 

    LinkedList<byte[]> list = new LinkedList<byte[]>(); 

    for (long i = 0; i < MaxNodeCount; ++i) 
    { 
     list.AddLast(new byte[LargeObjectSize]); 

     if (i % 100000 == 0) 
     { 
      Console.WriteLine("{0:N0} 'approx' extra bytes allocated.", 
       ((i + 1) * LargeObjectSize)); 
     } 
    } 
} 

Dies funktioniert wie erwartet dh virtueller Speicher wird benutzt und dann irgendwann erschöpft - 54GB in meiner Umgebung \ Konfiguration.

So scheint es, dass die Zuordnung einer Masse von langlebigen kleinen Objekten zu einem Teufelskreis im GC führen wird, da Generationsdurchläufe und Beförderungen gemacht werden, wenn der physische Speicher erschöpft ist - es ist eine Todesdrossel.

Update 2

Während das Problem zu untersuchen ich mit einer Reihe von Optionen gespielt \ Konfigurationen, die keinen nennenswerten Unterschied:

  • Server GC-Modus erzwingen.
  • Konfigurieren des GC mit niedriger Latenz.
  • Verschiedene Kombinationen von zwingen GC zu versuchen, GC zu amortisieren.
  • Min \ Max Prozess Arbeitssätze.
+0

Nein, aber sollte der Windows Virtual Memory Manager nicht automatisch mit dem Paging beginnen, zumindest bis zu einem gewissen Grad nach 16 GB? Was ist der Sinn von virtuellem Speicher, wenn er durch die Menge an physischem Speicher begrenzt ist? – brianberns

+0

Es ist konfigurierbar - eine Überprüfung lohnt sich. Die Probleme könnten von einer unerwarteten Politik bis zu einem hellen Funken reichen, der abblättert. –

+0

OK, ich habe die Auslagerungsdatei auf 30GB erhöht, aber es hatte keine Wirkung. Ich denke, der .NET-Garbage-Collector verhindert, dass ich Objekte mit mehr als 16 GB zuweisen kann, sodass das virtuelle Windows-Speichersystem nie die Chance hat, mit dem Paging zu beginnen. – brianberns

Verwandte Themen