2016-06-02 4 views
8

Ich bin auf der Suche nach einer Möglichkeit, große 3d Sparse Array-Struktur in den Speicher zu halten, ohne viel Speicher zu verschwenden. Hier habe ich ein Experiment mit Arrays von longs getan:Wie reserviert ein großes Array Speicher?

using System; 
using System.Diagnostics; 
using System.Runtime; 

namespace ConsoleApp4 
{ 
    public class Program 
    { 
     static Process proc = Process.GetCurrentProcess(); 
     const int MB = 1024 * 1024; 
     const int IMAX = 5; 
     const int JMAX = 100000000; 
     public static void ShowTextWithMemAlloc(string text) 
     { 
      proc.Refresh(); 
      Console.WriteLine($"{text,-30}WS64:{proc.WorkingSet64/MB,5}MB PMS64:{proc.PrivateMemorySize64/MB,5}MB"); 
      Console.ReadKey(); 
     } 
     public static void Main(string[] args) 
     { 
      Console.Write(" "); 
      ShowTextWithMemAlloc("Start."); 
      long[] lArray = new long[IMAX * JMAX]; 
      long[] l1Array = new long[IMAX * JMAX]; 
      long[] l2Array = new long[IMAX * JMAX]; 
      long[] l3Array = new long[IMAX * JMAX]; 
      ShowTextWithMemAlloc("Arrays created."); 
      lArray[IMAX * JMAX - 1] = 5000; 
      l1Array[IMAX * JMAX - 1] = 5000; 
      l2Array[IMAX * JMAX - 1] = 5000; 
      l3Array[IMAX * JMAX - 1] = 5000; 
      ShowTextWithMemAlloc("Last elements accessed."); 
      for (var i=IMAX-1; i>= 0; i--) 
      { 
       for (var j=0; j<JMAX; j++) 
       { 
        lArray[i * JMAX + j] = i * JMAX + j; 
       } 
       ShowTextWithMemAlloc($"Value for row {i} assigned."); 
      } 
      //lArray = new long[5]; 
      //l1Array = null; 
      //l2Array = null; 
      //l3Array = null; 
      //GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 
      //GC.Collect(); 
      //ShowTextWithMemAlloc($"GC.Collect done."); 
      ShowTextWithMemAlloc("Stop."); 
     } 
    } 
} 

Wenn Sie testen wollen, es stellen Sie die COMPlus_gcAllowVeryLargeObjects Umgebungsvariable (Projekteigenschaften -> Debug) auf 1 oder die JMAX ändern. Und dies ist die Ausgabe:

Start.      WS64: 14MB PMS64: 8MB 
Arrays created.    WS64: 15MB PMS64:15360MB 
Last elements accessed.  WS64: 15MB PMS64:15360MB 
Value for row 4 assigned.  WS64: 779MB PMS64:15360MB 
Value for row 3 assigned.  WS64: 1542MB PMS64:15360MB 
Value for row 2 assigned.  WS64: 2305MB PMS64:15361MB 
Value for row 1 assigned.  WS64: 3069MB PMS64:15361MB 
Value for row 0 assigned.  WS64: 3832MB PMS64:15362MB 
Stop.       WS64: 3844MB PMS64:15325MB 

Wenn ich den Speicherverbrauch im Task-Manager sehe, wie dies in Process.WorkingSet64 ist. Was ist die wahre Zahl? Warum wird bei der Zuweisung Speicher zugewiesen? Ist ein Array tatsächlich ein kontinuierlicher Speicher? Ist ein Array ein Array? Existieren Aliens? (Dramatische Hintergrundmusik)

Folge 2: Wir machen eine kleine Änderung:

  //lArray[i * JMAX + j] = i * JMAX + j; 
      var x= lArray[i * JMAX + j]; 

und nichts ändern (in der Ausgabe). Wo ist der Unterschied zwischen existent und nicht existent? (mehr dramatische Hintergrundmusik) Jetzt warten wir auf die Antwort eines der mysteriösen Menschen (Sie haben eine Nummer und ein kleines 'k' unter ihren Namen).

Folge 3: Eine weitere Änderung:

//lArray[IMAX * JMAX - 1] = 5000; 
    //l1Array[IMAX * JMAX - 1] = 5000; 
    //l2Array[IMAX * JMAX - 1] = 5000; 
    //l3Array[IMAX * JMAX - 1] = 5000; 
    //ShowTextWithMemAlloc("Last elements accessed."); 
    long newIMAX = IMAX-3; 
    long newJMAX = JMAX/10; 
    for (var i=0; i<newIMAX; i++) 
    { 
     for (var j=0; j<newJMAX; j++) 
     { 
      lArray[i * newJMAX + j] = i * newJMAX + j; 
      //var x= lArray[i * JMAX + j]; 
     } 
     //ShowTextWithMemAlloc($"Value for row {i} assigned."); 
    } 
    ShowTextWithMemAlloc($"{newIMAX*newJMAX} values assigned."); 

Der Ausgang:

Start.        WS64: 14MB PMS64: 8MB 
Arrays created.     WS64: 15MB PMS64:15369MB 
20000000 values assigned.   WS64: 168MB PMS64:15369MB 
Stop.        WS64: 168MB PMS64:15369MB 

PMS64 für eine Array (15.369-8)/4 = 3840MB Dies ist nicht sparse array, sondern teilweise gefülltes Array;). Ich benutze diese 168MB voll.

Antwort auf eine Frage "Warum verwenden Sie nicht die genaue Größe?". Weil ich es nicht weiß? Die Daten können aus mehreren benutzerdefinierten SQL-Dateien stammen. "Warum ändern Sie nicht die Größe?". Resize erstellt ein neues Array und kopiert die Werte. Dies ist die Zeit zu kopieren, Erinnerung und am Ende kommt der böse GC und isst dich.

Habe ich Speicher verloren. (Ich erinnere mich nicht. Die Aliens ?!) Und wenn ja, wie viel? 0, (3840-168) MB oder (15369-8-168) MB?

Epilog:

ist ein Kommentar ein Kommentar oder eine Antwort?

ist zusammenhängender Speicher tatsächlich zusammenhängenden Speicher?

Antworten geben Antworten? Geheimnisvoll. (more music)

(Scully: Mulder, Kröten fiel vom Himmel Mulder:. Ich denke, ihre Fallschirme nicht geöffnet)

Vielen Dank!

+3

* Ist ein Array tatsächlich ein fortlaufender zugeordneter Speicher? Ist ein Array ein Array? Existieren Aliens? * Ja. Ja. Wahrscheinlich, aber sie sind * weit weg *. –

+1

Ich vermute, dass die (eigentlich interessante) Frage, die Sie vielleicht verpasst haben, "Ist Speicher tatsächlich Speicher"? ... und vielleicht "okay, aber wenn Speicher Speicher ist, ist zusammenhängende Speicher tatsächlich zusammenhängende Speicher?" - Nein, ich weiß wirklich nicht genug darüber, um eine Antwort zu schreiben. – moreON

Antwort

6

Der Arbeitssatz ist nicht die Menge des zugewiesenen Speichers. Es sind die Seiten, die derzeit für den Prozess verfügbar sind. Windows implementiert verschiedene Richtlinien, und die Zahl ist im Allgemeinen schwer zu interpretieren.

Hier wurde der Speicher wahrscheinlich vom Betriebssystem als Nullen angefordert. Der erste Zugriff auf eine Seite macht tatsächlich eine auf Null gesetzte Seite verfügbar.

Sie sollten private Bytes betrachten.

Sie können .NET-Arrays nicht spärlich zuordnen. Wahrscheinlich sollten Sie eine Datenstruktur verwenden, die den Eindruck eines spärlichen Arrays vermittelt.

Ist ein Array tatsächlich ein fortlaufender zugeordneter Speicher?

Ja, aus der Sicht der CLR und des .NET-Codes läuft. Das Betriebssystem kann jedoch Tricks spielen, wie z. B. langsam Fehler in den Seiten beim ersten Lesen oder Schreiben.

Für "Episode 2" lautet die Antwort, dass die Fehler sowohl beim Lesen als auch beim Schreiben auftreten. Ich folge nicht ganz, was Episode 3 tut, aber ich nehme an, es berührt nur weniger Seiten.

Habe ich Speicher

Abfall zu sagen Dies ist komplizierter. Solange die Seiten nicht berührt werden, werden sie nicht physisch benutzt. Sie können zum Beispiel für den Dateicache oder für andere Programme verwendet werden. Sie zählen jedoch auf die Commit-Gebühr des Systems. Windows garantiert Ihnen, dass Sie diese Seiten für Sie verfügbar machen können. Bei einem wahlfreien Speicherzugriff wird Ihnen nicht mehr genügend Arbeitsspeicher zur Verfügung stehen. Linux garantiert das nicht. Es hat den OOM Killer als Milderung.

In einem extremen Fall, wenn Sie 1TB so zuweisen, müssen Sie die Summe von RAM und Größe der Auslagerungsdatei auch 1 TB überschreiten, obwohl keiner dieser Speicherplatz am Ende verwendet werden könnte.

Verwenden Sie Speicherabbilddateien. Hier ist die Datei der Sicherungsspeicher und RAM wird wie ein Cache behandelt. Dies würde sich genau so verhalten.