2016-06-02 18 views
8

Sto cercando un modo per tenere in memoria la grande struttura di array sparse 3d senza sprecare molta memoria. Qui ho fatto un esperimento con le matrici di Longs:Come una grande matrice alloca la memoria?

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."); 
     } 
    } 
} 

Se si desidera verificare che impostare la variabile d'ambiente COMPlus_gcAllowVeryLargeObjects (Progetto Proprietà -> Debug) per 1 o cambiare il jMax. E questo è l'output:

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 

Quando vedo il consumo di memoria in Task Manager è come questo in Process.WorkingSet64. Qual è il numero reale? Perché la memoria è assegnata al compito? Una matrice è effettivamente una memoria allocata continua? Un array è un array? Esistono gli alieni? (Musica di sottofondo drammatico)

Episodio 2: Facciamo un piccolo cambiamento:

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

e niente cambio (in uscita). Dov'è la differenza tra esistente e inesistente? (musica di sottofondo più drammatica) Ora stiamo aspettando la risposta di una delle persone misteriose (hanno un numero e una piccola "k" sotto il loro nome).

episodio 3: Un'altra modifica:

//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."); 

L'output:

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

PMS64 per un array (15.369-8)/4 = 3840MB Questo non array sparso, ma parzialmente riempito array;). Sto usando pieno questo 168 MB.

Risposta a qualche domanda "Perché non usi la misura esatta?". Perché io non lo so? I dati possono provenire da diversi SQL definiti dall'utente. "Perché non lo ridimensiona?". Ridimensiona crea un nuovo array e copia i valori. Questo è il momento di copiare, memoria e alla fine il malvagio GC arriva e ti mangia.

Ho perso memoria. (Non ricordo, gli alieni ?!) E quando si, quanto? 0, (3840-168) MB o (15369-8-168) MB?

Epilogo:

è un commento un commento o una risposta?

è memoria contigua effettivamente contigua alla memoria?

Le risposte danno risposte? Misterioso. (more music)

(Scully: Mulder, rospi appena sceso dal cielo Mulder:!. Credo che loro paracadute non si aprivano)

Grazie a tutti!

+3

* Una matrice è effettivamente una memoria allocata continua? Un array è un array? Esistono alieni? * Sì. Sì. Probabilmente, ma sono * lontani *. –

+1

Sospetto che la (davvero interessante) domanda che potresti aver perso sia "La memoria è effettivamente memoria"? ... e forse "okay, ma quando la memoria è memoria, la memoria è contigua alla memoria contigua?" - No, davvero non ne so abbastanza per scrivere una risposta. – moreON

risposta

6

Il working set non è la quantità di memoria allocata. È l'insieme di pagine attualmente disponibili per il processo. Windows implementa varie politiche intorno a questo e il numero generalmente è difficile da interpretare.

Qui, la memoria probabilmente è stata richiesta come azzerata dal sistema operativo. Il primo accesso a una pagina rende effettivamente disponibile una pagina a zero.

Si dovrebbe guardare ai byte privati.

Non è possibile allocare scarsamente array .NET. Probabilmente, dovresti considerare l'utilizzo di una struttura dati che fornisce l'impressione di una matrice sparsa.

Un array è effettivamente una memoria allocata continua?

Sì, dal punto di vista del CLR e del codice .NET in esecuzione. Il sistema operativo potrebbe giocare brutti scherzi, ad esempio, con pigrizia nelle pagine della prima lettura o scrittura.

Per "Episodio 2" la risposta è che l'errore si verifica sia per le letture che per le scritture. Non seguo abbastanza l'episodio 3 ma presumo che tocchi solo meno pagine.

ho sprecato memoria

Questo è più complicato da dire. Finché le pagine non vengono toccate, non sono fisicamente in uso. Possono essere utilizzati per la cache dei file per esempio o per altri programmi residenti. Contano per il costo del commit del sistema, però. Windows ti garantisce che può rendere disponibili quelle pagine. Non esaurirai la memoria con un accesso casuale alla memoria. Linux non lo garantisce. Ha l'OOM killer come una mitigazione.

In casi estremi, se si assegna 1 TB come quello, è necessario che la somma di RAM e dimensione del file di paging superi anche 1 TB anche se nessuno di questi spazi potrebbe essere utilizzato.

Considerare l'utilizzo di file mappati in memoria. Qui, il file è il backing store e la RAM viene trattata come una cache. Questo si comporterebbe esattamente allo stesso modo.

Problemi correlati