2015-11-29 8 views
5

Continuo a sperimentare con C. Ho questo programma che ti permette di decidere quanta RAM vuoi mangiare.Sperimentare con C - Perché non è possibile allocare e utilizzare 2 GB di memoria?

char * eatRAM() 
{ 
    unsigned long long toEat; 
    unsigned long long i = 0; 
    float input; 
    char * pMemory = NULL; 
    int megaByte = 1048576; 

    puts("How much RAM do you want to eat? (in Mega Bytes)"); 
    puts("NOTE: If you want to eat more RAM than you have available\nin your system, the program will crash"); 
    printf("\n>> MB: "); 
    scanf("%f", &input); 

    toEat = (unsigned long long)(input * megaByte); 
    pMemory = malloc(toEat); 

    printf("\n\nEating in total: %llu Bytes\n", toEat); 
    puts("Check your task manager!\n"); 

    if(pMemory != NULL) 
    { 
     printf("\n\nEating in total: %llu Bytes\n", toEat); 
     puts("Check your task manager!\n"); 

     for(i; i < toEat; i++) 
     { 
      pMemory[i] = 'x'; 
     } 
    } 
    else 
    { 
     puts("\nSeems like that amount of memory couldn't be allocated :(\n"); 
    } 
    return pMemory; 
} 

domanda aggiornato:

Il fatto è che ... se entro per esempio 1024MB funziona, posso vedere nel task manager che sta usando 1GB di RAM. Anche se entro 1500MB funziona ..

Ma se entro 2048MB si dice

Sembra come quella quantità di memoria non poteva essere assegnato :(

o anche se inserisco 1756MB

Ricorda che sono nuovo di C, forse sto omettendo qualcosa di importante a come il sistema operativo mi consente di accedere alla memoria, quale potrebbe essere?

+0

malloc probabilmente fallisce e restituisce null, controllare che –

+0

si blocca perché si tenta di accedere alla memoria anche se l'allocazione non è riuscita, è necessario controllare 'pMemory! = NULL' prima di provare a utilizzarlo. Inoltre, non dovresti lanciare 'malloc()', in generale non lanciare mai da 'void *' a nessun altro puntatore. –

+0

Quanta RAM ha il tuo computer? –

risposta

5

Un processo a 32 bit su Windows ha uno spazio di indirizzi di 2 gigabyte disponibile per impostazione predefinita. La metà inferiore dello spazio di indirizzamento full pow (2, 32), i primi 2 GB sono usati dal sistema operativo. Poiché quasi nessuno usa più un sistema operativo a 32 bit, puoi ottenere 4 GB quando colleghi il tuo programma a/LARGEADDRESSAWARE.

Lo spazio della macchina virtuale da 2 GB deve essere condiviso da codice e dati. Generalmente il tuo programma carica a 0x00400000, qualsiasi DLL del sistema operativo che usi (come kernel32.dll e ntdll.dll) ha indirizzi di carico elevato (oltre 0x7F000000). E almeno lo stack del thread di avvio e l'heap del processo predefinito vengono creati prima dell'avvio del programma, i loro indirizzi sono generalmente imprevedibili.

Il tuo programma sarà soggetto a attacchi virali compressi di strizzacervelli nella maggior parte delle installazioni di sistemi operativi, con l'iniezione di DLL che forniscono "servizi" come anti-malware e archiviazione su cloud. L'indirizzo di caricamento di queste DLL è imprevedibile. Inoltre, tutte le DLL collegate con te stesso vengono caricate implicitamente all'avvio del programma. Pochi programmatori prestano attenzione al loro indirizzo di base preferito e lo lasciano al default, 0x1000000. Puoi vedere queste DLL dalla finestra Moduli del debugger. Tali DLL hanno spesso il proprio CRT e tendono a creare i propri heap.

Le allocazioni effettuate dall'utente, in particolare quelle molto grandi che non provengono dall'heap a bassa frammentazione, devono trovare lo spazio degli indirizzi nei fori rimasti tra il codice esistente e le allocazioni dei dati. Se ottieni 1500 MB, la tua VM è abbastanza pulita. In generale, ci si mette nei guai oltre i 650 MB, diventando rapidamente meno quando il programma è in esecuzione da un po 'e frammentando lo spazio della VM. I fallimenti di allocazione sono quasi sempre causati dal fatto che il sistema operativo non riesce a trovare un buco abbastanza grande, non perché non ne abbiate ancora abbastanza. La somma dei fori può essere notevolmente superiore alla richiesta di allocazione non riuscita.

Questi dettagli stanno rapidamente diventando un racconto popolare, ci sono ben pochi motivi per continuare a scegliere x86. L'obiettivo x64 e la frammentazione dello spazio degli indirizzi non saranno un problema per i prossimi 20 anni, molto difficile da frammentare 8 terabyte di VM. Con un sacco di spazio per la testa a crescere oltre.

Quindi dovrebbe essere ovvio il motivo per cui non è possibile ottenere 2048 MB, non è possibile ottenere tutto. Ottieni ulteriori informazioni da SysInternals 'VMMap utility, ti mostra come viene scolpita la VM. E Mark Russinovich 'blog post e il libro danno molto sfondo.

+0

Grazie per aver dedicato del tempo a dare una risposta così ben supportata! Continuerai a ricercare e praticare! - Saluti! –

0

L'allocazione non funzionerà mai se la quantità di memoria libera rimanente è inferiore all'importo che si sta tentando di allocare.

Inoltre, subito dopo questa riga:

pMemory = (char *) malloc(toEat); 

Aggiungere il seguente:

if (!pMemory){ 
    printf("Can't allocate memory\n"); 
    return NULL; 
} 

In questo modo, invece di ricevere "segmentation fault" messaggi correlati, vedrete un "Can' t allocare memoria "messaggio invece e la funzione restituirà NULL.

Assicurati di eseguire un controllo del valore simile nelle funzioni che chiamano la funzione eatRam o riceverai messaggi di "errore di segmentazione". e inoltre, usa i debugger come gdb.

+1

Grazie a Mike per rispondere. In realtà ho più di 5 GB di RAM DISPONIBILE al momento dell'esecuzione dei test con 2048 MB, cosa ne pensi? Inoltre, ho aggiornato alcuni minuti fa il mio codice in modo che gestisse correttamente il ritorno di malloc. Grazie ancora! –

+2

@JuanBonnett si noti che l'uso di 'malloc' significa che la memoria che si sta utilizzando è un gigantesco blocco di codice, anche se si dispone di 2-3 + GB di memoria libera che potrebbe non avere (diciamo) 1 GB di un blocco libero. Inoltre, penso di aver letto da qualche parte che a causa di questo motivo, Windows ha alcune "limitazioni di blocco", quindi le applicazioni non cercheranno di allocare memoria da altre app o qualcosa del genere. – TomTsagk

3

È un limite del sistema operativo anziché un limite C.

Per utilizzare più di 4 GB di sistema, è necessario che sia in esecuzione un sistema operativo a 64 bit e che per un singolo processo di indirizzo superiore a 4 GB sia necessario creare un'app a 64 bit. Win32 ha un limite di memoria di 2 GB per processo. 5 GB di RAM fisica sono in gran parte irrilevanti dal momento che la memoria è virtualizzata.

A prescindere dai limiti teorici dei sistemi e delle applicazioni a 32 e 64 bit, un sistema operativo può ancora imporre limiti. Diverse versioni ed edizioni (Home, Pro, Server, ecc.) Di Windows, ad esempio, impongono limiti specifici per ragioni commerciali.

Una risposta specifica nel tuo caso richiederebbe informazioni sul tuo sistema, sulla toolchain e sulle opzioni di compilazione applicate. Se si utilizza Windows e VC++, è necessario considerare l'opzione /LARGEADDRESAWARE; non è abilitato per impostazione predefinita nel compilatore a 32 bit, ma Win32 ha un limite predefinito di 2 GB in ogni caso, a meno che non sia abilitato physical address extension.

Credo che un processo a 32 bit in esecuzione su Win64 possa indirizzare lo spazio di indirizzi completo a 32 bit a 32 bit, ma in questo caso sarà sicuramente necessario creare con /LARGEADDRESAWARE.Anche allora non tutto lo spazio sarà disponibile per l'heap e ogni singola allocazione deve essere contigua, quindi potrebbe essere limitata dalle precedenti allocazioni e dalla frammentazione dell'heap.

+0

Grazie per aver dedicato del tempo a dare una risposta così ben supportata! Continuerai a ricercare e praticare! - Saluti! –

Problemi correlati