2009-06-23 13 views
7

Background: sto scrivendo un programma C++ che lavora con grandi quantità di dati geografici e desidero caricare grossi pezzi da elaborare in un'unica operazione. Sono costretto a lavorare con un'app compilata per macchine a 32 bit. La macchina su cui sto eseguendo un sistema operativo a 64 bit (Windows 7) e ha 6 gig di ram. Utilizzando MS VS 2008.Quanta memoria dovresti essere in grado di allocare?

Ho il seguente codice:

byte* pTempBuffer2[3]; 
try 
{ 
    //size_t nBufSize = nBandBytes*m_nBandCount; 
    pTempBuffer2[0] = new byte[nBandBytes]; 
    pTempBuffer2[1] = new byte[nBandBytes]; 
    pTempBuffer2[2] = new byte[nBandBytes]; 
} 
catch (std::bad_alloc) 
{ 
    // If we didn't get the memory just don't buffer and we will get data one 
    // piece at a time. 
    return; 
} 

speravo che sarei stato in grado di allocare memoria fino a quando l'applicazione ha raggiunto il limite di 4 gigabyte di 32 bit di indirizzamento. Tuttavia, quando nBandBytes è 466.560.000 il nuovo lancio std :: bad_alloc al secondo tentativo. A questo punto, il valore di working set (memoria) per il processo è 665,232 K Quindi, non sembra che sia in grado di ottenere anche solo un gig di memoria allocata.

È stato menzionato un limite di 2 gig per le applicazioni in Windows a 32 bit che può essere esteso a 3 gig con l'opzione/3GB per win32. Questo è un buon consiglio in questo ambiente, ma non è pertinente in questo caso.

Quanta memoria si dovrebbe essere in grado di allocare sotto il sistema operativo a 64 bit con un'applicazione a 32 bit?

+0

Ho trovato questo riferimento sul web: "Se si esegue come un'app a 32 bit su un sistema operativo a 64 bit, si ottiene tutto lo spazio degli indirizzi 4G e tutto ciò potrebbe essere supportato dalla memoria fisica (se si avere la RAM) anche senza usare te stessi puntatori a 64 bit. " dal blog: http://blogs.msdn.com/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx – Bill

+0

Sulla mia macchina a 32 bit sono in grado di allocare 466.560.000 × 3 byte in test semplice. Sembra che la memoria di processo sia già frammentata nel punto di allocazione nel tuo caso. –

+1

Ho avuto difficoltà a scegliere una risposta per contrassegnare corretta su questa domanda. Credo che la risposta sia complicata e dipende da molti fattori. I file mappati in memoria sono una buona risposta, ma la causa principale di questo problema sembra essere la frammentazione della memoria. bke1 ha sottolineato buoni strumenti per guardare la memoria, e molte persone hanno parlato della frammentazione della memoria, ma ho scelto la prima risposta che ha chiaramente indicato il problema e ha dato limiti difficili (4 Gig a 64 bit e le bandiere giuste.) – Bill

risposta

10

Tanto quanto l'OS vuole darti. Per impostazione predefinita, Windows consente a un processo a 32 bit di avere 2 GB di spazio indirizzo. E questo è diviso in diversi blocchi. Un'area è messa da parte per lo stack, gli altri per ogni eseguibile e dll che viene caricato. Qualunque cosa sia rimasta può essere allocata dinamicamente, ma non è garantito che sarà un grosso pezzo contiguo. Potrebbe essere diversi pezzi più piccoli di un paio di centinaia di MB ciascuno.

Se si compila con la bandiera LARGEADDRESSAWARE, a 64 bit di Windows vi permetterà di utilizzare lo spazio di indirizzo completo 4GB, che dovrebbe aiutare un po ', ma in generale,

  • non si deve presumere che la disposizione la memoria è contigua Dovresti essere in grado di lavorare con più allocazioni più piccole invece di alcune grandi, e
  • Dovresti compilarlo come applicazione a 64 bit se hai bisogno di molta memoria.
+0

"non dovresti dare per scontato che la memoria disponibile sia contigua, dovresti essere in grado di lavorare con più allocazioni più piccole invece di alcune grandi, e" Questo è sbagliato quando Windows usa la memoria paginata e l'app è contigua per uno grande pezzo – Lodle

+1

Lodle, si confonde lo spazio degli indirizzi e lo spazio di indirizzi liberi. Per esempio. una delle forme più comuni di frammentazione è causata dal codice stesso. L'EXE e le DLL non vengono caricati a partire da 0x00000000. – MSalters

+0

@Lodle: No, l'app vede uno spazio di indirizzamento contiguo, ma le variabili exe, dll, stack e statiche sono tutte caricate in indirizzi diversi all'interno di quello spazio indirizzo. – jalf

6

su Windows 32 bit, il processo normale può richiedere 2 GB al massimo, ma con lo switch /3GB può raggiungere i 3 GB (per Windows 2003).

ma nel tuo caso penso che stai allocando memoria contigua, e quindi si è verificata l'eccezione.

+3

+1 - mai considerato il fatto che l'assegnazione di un array contiguo può solo darti la più grande quantità di memoria "contigua" gratis! Davvero un buon punto. –

+1

L'opzione/3GB è un po 'pericolosa. Molti driver non sono stati testati con lo switch, pertanto potrebbero diventare instabili quando il sistema operativo è limitato a 1 GB. Non importa però, dato che è in esecuzione su un sistema Windows a 64 bit. – jalf

+1

Per aiutarmi a capire cosa stai dicendo, proverò a riformularlo. Stai dicendo che se alloco la memoria in blocchi più piccoli sarò in grado di ottenere più memoria totale allocata? – Bill

1

Con nBandBytes a 466,560,000, si sta tentando di allocare 1,4 GB. Un'app a 32 bit in genere ha accesso solo a 2 GB di memoria (di più se si avvia con/3 GB e l'eseguibile è contrassegnato come grande spazio degli indirizzi). Potrebbe essere difficile trovare molti blocchi di spazio di indirizzi contigui per i tuoi grossi pezzi di memoria.

Se si desidera allocare gigabyte di memoria su un sistema operativo a 64 bit, utilizzare un processo a 64 bit.

+0

Come si ottiene 1,4 GB? Stai supponendo che un byte sia 4 byte? : p – jalf

+0

3 * 466,560,000. Sta assegnando 3 array. – Michael

+0

Corretto, speravo di essere in grado di allocare 1,3 gigabyte di memoria, e sono rimasto sorpreso quando non ci sono riuscito. – Bill

1

Dovresti essere in grado di allocare un totale di circa 2 GB per processo. This article (PDF) spiega i dettagli. Tuttavia, probabilmente non sarai in grado di ottenere un singolo blocco contiguo che sia persino vicino a quello grande.

1

Anche se si allocano in blocchi più piccoli, non è possibile ottenere la memoria necessaria, soprattutto se il programma circostante ha un comportamento di memoria imprevedibile o se è necessario eseguire su sistemi operativi diversi. Nella mia esperienza, lo spazio heap su un processo a 32 bit ha un limite di circa 1,2 GB.

A questa quantità di memoria, consiglio di scrivere manualmente sul disco. Avvolgi i tuoi array in una classe che gestisce la memoria e scrive su file temporanei quando necessario. Speriamo che le caratteristiche del tuo programma siano tali da poter memorizzare in modo efficace parti di tali dati senza incidere troppo sul disco.

4

È possibile allocare tutta la quantità di memoria che il file di pagina consente, anche senza l'opzione/3GB, è possibile allocare 4 GB di memoria senza troppe difficoltà.

Leggi this article per una buona panoramica su come pensare alla memoria fisica, alla memoria virtuale e allo spazio degli indirizzi (tutti e tre sono cose diverse). In poche parole, hai esattamente la stessa quantità di memoria fisica della RAM, ma la tua app in realtà non ha alcuna interazione con quella memoria fisica - è solo un posto comodo dove archiviare i dati nella tua memoria virtuale. La memoria virtuale è limitata dalla dimensione del file di paging e l'importo che l'app può utilizzare è limitato dalla quantità di altre app utilizzate (anche se è possibile allocarne altre, a condizione che non vengano effettivamente utilizzate). Lo spazio degli indirizzi nel mondo a 32 bit è 4 GB. Di questi, 2 GB sono assegnati al kernel (o 1 GB se si utilizza l'opzione/3BG). Dei 2 GB rimasti, alcuni saranno esauriti dal tuo stack, alcuni dal programma che stai correntemente eseguendo (e tutte le DLL, ecc.). Diventerà frammentato, e riuscirai a ottenere così tanto spazio contiguo - questo è dove la tua allocazione sta fallendo. Ma dal momento che lo spazio degli indirizzi è solo un modo conveniente per accedere alla memoria virtuale che hai assegnato per te, è possibile allocare molta più memoria e portarne alcuni pezzi nello spazio degli indirizzi pochi alla volta.

Raymond Chen has an example su come allocare 4 GB di memoria e mapparne una parte in una sezione del proprio spazio indirizzo.

Sotto Windows a 32 bit, l'allocatable massimo è 16TB e 256TB in Windows a 64 bit.

E se sei veramente interessato a come funziona la gestione della memoria in Windows, leggi this article.

2

Durante il progetto ElephantsDream, Blender Foundation con Blender 3D ha avuto problemi simili (anche se su Mac). Non è possibile includere il link ma google: problema di allocazione della memoria di blender3d e sarà il primo elemento.

La soluzione riguardava la mappatura dei file. Non ho provato da solo ma puoi leggerlo qui: http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx

1

Sysinternals VMMap è ideale per indagare la frammentazione dello spazio degli indirizzi virtuali, che probabilmente limita la quantità di memoria contigua che è possibile allocare. Raccomando di impostarlo per visualizzare lo spazio libero, quindi ordinare per dimensione per trovare le aree libere più grandi, quindi ordinare per indirizzo per vedere cosa separa le aree libere più grandi (probabilmente le DLL rebased, le regioni di memoria condivisa o altri heap).

Evitare allocazioni contigue estremamente grandi è probabilmente il migliore, come altri hanno suggerito.

L'impostazione LARGE_ADDRESS_AWARE=YES (come suggerito da jalf) è buona, a condizione che le librerie da cui dipende l'applicazione siano compatibili con esso. In tal caso, è necessario testare il codice con il set di chiavi del registro AllocationPreference per abilitare l'allocazione dell'indirizzo virtuale top-down.

+0

Buona idea - proverò VMMap. – Bill

Problemi correlati