2009-07-10 7 views
18

Mi chiedo il motivo per cui non sono in grado di allocare più di 1.000 MB di memoria nel mio processo .NET a 32 bit. La seguente mini applicazione genera una OutOfMemoryException dopo aver assegnato 1.000 MB. Perché 1.000 MB, e non dire 1.8 GB? C'è un ambiente che posso cambiare a livello di processo?Assegnazione di più di 1.000 MB di memoria nel processo .NET a 32 bit

static void Main(string[] args) 
{ 
    ArrayList list = new ArrayList(); 
    int i = 0; 
    while (true) 
    { 
     list.Add(new byte[1024 * 1024 * 10]); // 10 MB 
     i += 10; 
     Console.WriteLine(i); 
    } 
} 

PS: raccolta dei rifiuti non aiuta.

Modifica, per chiarire cosa voglio: Ho scritto un'applicazione server che tratta grandi quantità di dati prima di scrivere su database/disco. Invece di creare file temporanei per tutto, ho scritto una cache in memoria, che rende il tutto super-veloce. Ma la memoria è limitata e così ho cercato di scoprire quali sono i limiti. E mi sono chiesto perché il mio piccolo programma di test ha lanciato OutOfMemoryException dopo esattamente 1.000 MB.

risposta

7

Il limite di spazio dell'indirizzo virtuale di un processo Win32 è 1,5 GB (non completamente vero). Inoltre nei framework .NET esiste un limitatore della% di memoria che un processo .NET può consumare. Machine.config ha un elemento processModel con un attributo memoryLimit che è la% della memoria disponibile che un processo può consumare. Il valore predefinito è 60%.

Se la macchina in uso ha 2 GB di memoria o non hai abilitato l'interruttore/3GB nel tuo BOOT.INI, avrai circa 1,3 GB di memoria per processo.

Non riesco a trovare l'articolo della Knowledge Base ma, se non ricordo male, .NET 1.x non può superare il limite di 1,5 GB (1,8 GB?) Indipendentemente dalle impostazioni.

http://blogs.msdn.com/tmarq/archive/2007/06/25/some-history-on-the-asp-net-cache-memory-limits.aspx http://social.msdn.microsoft.com/Forums/en-US/clr/thread/c50ea343-b41b-467d-a457-c5a735e4dfff http://www.guidanceshare.com/wiki/ASP.NET_1.1_Performance_Guidelines_-_Caching#Configure_the_Memory_Limit

+1

Grazie, mi dà un'idea. Tuttavia, i collegamenti non sono davvero utili. –

+0

Solo il CLR del server utilizza la configurazione memoryLimit. La workstation CLR utilizza sempre la quantità di memoria che può ottenere. – ezolotko

+0

@ ezolotko - Non ero mai consapevole che ci fosse una differenza. – MyItchyChin

16

Avere enormi blocchi di memoria non è mai una buona idea, anche a 64 bit. Hai grossi problemi con la memoria e la frammentazione contigue.

Il problema qui è trovare un blocco contiguo. Potresti provare a abilitare la modalità 3gb (che potrebbe aiutarti a trovare qualche byte in più) ma I davvero sconsigliamo. Le risposte sono qui:

  • utilizzare meno memoria
  • utilizzare un database/file system
  • uso x64

Si potrebbe anche voler leggere Eric Lippert's blog (che sembra avere un blog per ogni domanda .NET comune ...)

+2

Johannes, perché avere più spazio di indirizzamento NON rende più facile trovare più spazio di indirizzamento contiguo ??? Sono completamente confuso dal tuo commento. Puoi spiegare? –

+0

@Eric - Sono contento che non sia stato solo io ... –

+0

Per favore, vedi il mio chiarimento. Sto già usando db/fs. –

2

Di recente ho fatto ampia profilazione giro limiti di memoria in .NET in un processo a 32 bit. Siamo tutti bombardati dall'idea che possiamo allocare fino a 2,4 GB (2^31) in un'applicazione .NET ma sfortunatamente questo non è vero :(. Il processo di applicazione ha così tanto spazio da usare e il sistema operativo fa un grande Tuttavia, lo stesso .NET sembra avere il proprio overhead che rappresenta approssimativamente 600-800 MB per le tipiche applicazioni del mondo reale che spingono il limite di memoria. Ciò significa che non appena si assegna un array di numeri interi che richiede circa 1.4GB, si dovrebbe aspettare di vedere un OutOfMemoryException().

Ovviamente in 64bit, questo limite si verifica così tardi (la Chat in 5 anni :)), ma la dimensione generale di tutto ciò che nella memoria cresce anche (mi sto trovando va da ~ 1.7 a ~ 2 volte) a causa della maggiore dimensione della parola.

Quello che so per certo è che l'idea di memoria virtuale dal sistema operativo NON ti dà assolutamente spazio di allocazione praticamente infinito all'interno di un unico processo. È solo lì in modo che l'intero 2,4 GB è indirizzabile a tutte le (molte) applicazioni in esecuzione contemporaneamente.

Spero che questa intuizione aiuti un po '.

Originariamente ho risposto qualcosa legato qui (io sono ancora un newby quindi non sono sicuro di come dovrei fare questi collegamenti):

Is there a memory limit for a single .NET process

-2

Mi dispiace davvero se non ho avuto la tua punto ma:

static void Main(string[] args) 
{ 
    ArrayList list = new ArrayList(); 
    int i = 0; 
    while (true) 
    { 
     using(byte newBt = new byte[1024 * 1024 * 10]) 
     { 
      list.Add(newBt); // 10 MB 
      i += 10; 
      Console.WriteLine(i); 
     } 
    } 
} 

Hai provato il metodo di utilizzo? E questa potrebbe essere una domanda stupida, ma perché hai creato un ciclo eterno? O se provi il codice striscia i simboli>.> XD.

Fonte: http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

+1

Ho modificato la risposta per correggere la formattazione del codice. La prossima volta che hai bisogno di inserire il codice incollalo, selezionalo e premi CTRL + K o l'icona {}, verrà automaticamente formattato – BlackBear

+0

Questo manca totalmente il punto della domanda. Il ciclo infinito alloca la memoria fino a quando non riesce, determinando così la quantità massima di memoria che il processo può consumare. Il codice non viene compilato perché tenta di assegnare un array di byte a un byte. Inoltre, nessuno di questi strumenti è IDisposable. E se liberasse la memoria ad ogni iterazione, avrebbe interrotto il test (alla fine avrebbe riportato circa (2^31)/10, ma quel numero non avrebbe avuto nulla a che fare con quanta memoria poteva allocare). –

-1

Credo che il problema qui è che questa applicazione sarà l'aggiunta di 10 MB per ogni ciclo che fa, e il ciclo è: "while (true)" il che significa che l'aggiunta di questi 10Mbs fino alla l'applicazione viene interrotta. Quindi, se dovesse girare per 100 loop, avrebbe aggiunto circa 1 GB alla RAM, e suppongo che lo avrebbe fatto in meno di 30 secondi. Il mio punto è che stai provando a 10 megabyte di memoria per ciclo, in un ciclo senza fine

0

Puoi allocare MOLTO PIÙ memoria di ~ 2 GB costruendo l'applicazione in un'architettura a 64 bit, che richiede di creare un nuova configurazione di build in Visual Studio e quella build dell'applicazione verrà eseguita solo su versioni a 64 bit di Windows. In .NET, utilizzando l'opzione di compilazione "Qualsiasi CPU" predefinita per l'applicazione, trovo che sono in grado di allocare solo circa 1,5 GB di memoria dall'heap (anche sulla macchina Windows a 64 bit), perché l'applicazione in realtà funziona solo in modalità a 32 bit quando è costruito in modalità "Qualsiasi CPU". Ma compilando l'architettura x64, puoi allocare molta più memoria dall'heap durante l'esecuzione della tua applicazione, e ti spiegherò come creare una build x64 per la tua applicazione qui sotto:

Di nuovo, usando il normale (impostazione predefinita) Opzione di costruzione "Qualsiasi CPU" nel progetto .NET, l'applicazione verrà SEMPRE eseguita in modalità a 32 bit, anche su un sistema operativo Windows a 64 bit. Pertanto non sarà possibile allocare più di 1,5 a 2 GB di memoria RAM durante l'esecuzione dell'applicazione. Per eseguire l'applicazione .NET in modalità a 64 bit, è necessario accedere al gestore configurazione build e creare un tipo di build per l'architettura x64, quindi ricompilare esplicitamente il programma per x64 utilizzando tale tipo di build. L'opzione della modalità x64 build può essere creato per la soluzione .NET utilizzando le seguenti operazioni:

  1. in Visual Studio "Solution Explorer" riquadro, fate clic destro sull'icona di soluzione e scegliere l'opzione "Configuration Manager" da il menu a comparsa. Si aprirà la finestra di dialogo di configurazione "Configuration Manager" per il file .NET Solution.
  2. Nella parte destra della finestra di dialogo "Configuration Manager" di build, fare clic sulla freccia giù e selezionare l'opzione "& ltnew & gt". Questo aprirà la finestra di dialogo "Nuova piattaforma di soluzione".
  3. Nella finestra di dialogo "Nuova piattaforma di soluzione", per l'opzione "Piattaforma", selezionare "x64" dal menu a discesa. Quindi fare clic sul pulsante "OK" e la nuova opzione di costruzione x64 sarà ora disponibile nella finestra di dialogo Gestore configurazione.
  4. Quindi, nella finestra di dialogo "Configuration Manager", selezionare "x64" nel menu a discesa "Piattaforma di soluzioni attive". Fare clic sul pulsante "Chiudi".
  5. Nel riquadro "Esplora soluzioni" di Visual Studio, fare clic con il pulsante destro sull'icona Progetto CS e scegliere l'opzione "Proprietà" dal menu a comparsa (l'ultima opzione in fondo a questo menu). Questo aprirà la finestra delle proprietà del progetto CS.
  6. Sul lato sinistro della finestra delle proprietà del progetto CS, fare clic sulla scheda "Crea" per mostrare le proprietà di costruzione per il progetto di codice. Nella parte superiore di questa finestra, si noti che la "Piattaforma" dovrebbe ora dire "x64" (in contrasto con l'opzione predefinita "Qualsiasi CPU"). Se il menu a discesa "Piattaforma" non mostra "x64", dovresti selezionarlo ora.
  7. Quindi crea il tuo codice e nella cartella "bin", dovresti ora avere una cartella x64 con il nuovo build a 64 bit della tua applicazione al suo interno.

Utilizzando un 64-bit di compilazione della vostra applicazione su un 64-bit di Windows OS permetterà il vostro programma di destinare molto di più di ~ 2GB di memoria, presumibilmente fino a 2^64 spazi di indirizzi (se avete la RAM e spazio su disco disponibili, che sono i veri fattori limitanti al momento di scrivere questa risposta).

Se si sta ancora esaurendo la memoria nell'applicazione, è anche possibile aumentare le dimensioni del file di memoria di Windows. Su Windows, il file di paging consente al sistema operativo di spostare la memoria dalla RAM al disco, se esaurisce lo spazio di memoria RAM. Tuttavia, il trasferimento di sezioni di memoria RAM su e dal disco può comportare un notevole risparmio di tempo, pertanto potrebbe essere un vero colpo alle prestazioni della tua applicazione. Indipendentemente dalle prestazioni, aumentando le dimensioni della pagina, è possibile (in teoria) rendere il file di pagina tanto grande quanto lo spazio disponibile sull'unità C: del computer Windows. In tal caso, l'applicazione sarà in grado di allocare, ad esempio, fino a 4 TB di memoria (o qualsiasi quantità di memoria a cui è impostata la dimensione del file di pagina) durante l'esecuzione del programma. Per modificare le impostazioni del file di paging per la vostra macchina Windows, effettuare le seguenti operazioni:

  1. Aprire la finestra di dialogo "Proprietà di sistema" facendo clic destro su "Questo PC" e scegliendo l'opzione "Proprietà" dal menu a comparsa. Questo può essere fatto anche nelle versioni successive di Windows (Windows 10, Win 2012 Server, ecc ...) andando su "Start" & gt "Pannello di controllo" & gt "Sistema e sicurezza" & gt "Sistema".
  2. Sul lato sinistro della finestra di dialogo "Sistema", fare clic sull'opzione "Proprietà di sistema avanzate". Questo mostrerà la scheda "Avanzate" della legacy "Proprietà del sistema" per Windows.
  3. Nella scheda "Avanzate" della finestra di dialogo "Proprietà del sistema", fare clic sul pulsante "Impostazioni" nella casella "Prestazioni". Si aprirà la finestra di dialogo "Opzioni di prestazione".
  4. Nella finestra di dialogo "Opzioni prestazioni", fare clic sulla scheda "Avanzate" per visualizzare le impostazioni della dimensione corrente per il file di pagine di memoria di Windows.
  5. Per aumentare la dimensione del file di pagina, fare clic sul pulsante "Cambia" per aprire la finestra di dialogo "Memoria virtuale".
  6. Nella finestra di dialogo "Memoria virtuale", selezionare l'unità "C:", quindi in "Dimensioni personalizzate", impostare le dimensioni "Iniziale" e "Massimo". È possibile utilizzare qualsiasi dimensione fino alla quantità massima di spazio libero sull'unità C: ma questa modifica riserva lo spazio per il file di paging sul disco rigido.
  7. Quindi fare clic su "OK" in tutte le finestre di dialogo per confermare le nuove impostazioni. Quindi riavviare il computer per assicurarsi che tutte le modifiche siano state completate correttamente e che le nuove impostazioni del file di paging siano operative.

Comunque, spero che questo aiuta le persone a capire il motivo per cui si può incorrere in questo 1,5-2 GB questione della prescrizione di memoria in un'applicazione .NET, anche se in esecuzione su una macchina Windows a 64 bit. Questo può essere un problema molto confuso per le persone e spero che la mia spiegazione abbia un senso. Sentitevi liberi di inviarmi messaggi con domande su questa risposta, se necessario.