2010-09-10 8 views
11

realloc viene utilizzato per riallocare la memoria in modo dinamico.Cosa farebbe realloc se non ci fosse spazio sequenziale di memoria?

Supponiamo di aver assegnato 7 byte utilizzando la funzione malloc e ora desidero estenderlo a 30 byte.

Cosa succederà in background se non c'è spazio sequenziale (continuo in una riga) di 30 byte nella memoria?

C'è qualche errore o la memoria verrà allocata in parti?

risposta

11

realloc lavori dietro le quinte o meno così:

  • se c'è abbastanza spazio libero dietro il blocco corrente per soddisfare la richiesta, di estendere il blocco corrente e restituire un puntatore all'inizio del blocco .
  • Altrimenti se c'è un blocco libero abbastanza grande altrove, quindi allocare quel blocco, copiare i dati dal vecchio blocco, liberare il vecchio blocco e restituire un puntatore all'inizio del nuovo blocco
  • restituendo NULL.

Quindi, è possibile verificare per il mancato testando per NULL, ma essere consapevoli del fatto che non sovrascrivere il vecchio puntatore troppo presto:

int* p = malloc(x); 
/* ... */ 
p = realloc(p, y); /* WRONG: Old pointer lost if realloc fails: memory leak! */ 
/* Correct way: */ 
{ 
    int* temp = realloc(p, y); 
    if (NULL == temp) 
    { 
    /* Handle error; p is still valid */ 
    } 
    else 
    { 
    /* p now possibly points to deallocated memory. Overwrite it with the pointer 
     to the new block, to start using that */ 
    p = temp; 
    } 
} 
+0

È questo il 'realloc' funziona per tutte le implementazioni? –

+0

@CoolGuy: Alcune implementazioni potrebbero non (essere in grado di) fare quel primo passo di estendere il blocco corrente, ma altrimenti questo è il comportamento osservabile di 'realloc' per tutte le implementazioni. –

1

Dal man page:

realloc() restituisce un puntatore alla memoria appena allocata, che è opportunamente allineati per qualsiasi tipo di variabile e possono essere diverse da PTR, o NULL se la richiesta non riesce.

Quindi, in altre parole, per rilevare l'errore, è sufficiente verificare se il risultato era NULL.

MODIFICA: come indicato nel commento, se la chiamata fallisce, la memoria originale non viene liberata.

+2

Vale la pena notare dalla pagina man: Se realloc() fallisce il blocco originale non viene toccato; non è liberato o spostato. –

6

realloc riuscirà solo se è possibile restituire un blocco di memoria contiguo ("sequenziale" nelle parole). Se questo blocco non esiste, restituirà NULL.

+4

@Mark: la memoria originale non viene modificata. Un bug comune in questo contesto è 'x = realloc (x)' - devi fare 'newX = realloc (x)' per evitare di perdere la x originale in caso di errore. –

+0

@Steve Townsend - Questo è solo quando fallisce il rito? Quando ha successo, libera il puntatore originale. E chi Mark in questa pagina? O_o –

+0

Immagino ci sia stato un errore. Il primo commento è stato mostrato dall'utente sharptooth e ora è cambiato anche se entrambi sono rivolti a Mark. Era un bug? :-P –

1

In generale, dipende dall'implementazione. Su x86 (-64) Linux, credo che l'algoritmo standard di malloc doug lea allocherà sempre un minimo di una pagina x86 standard (4096 byte), quindi per lo scenario descritto sopra, si resetteranno i limiti per contenere i byte aggiuntivi. Quando si tratta, ad esempio, di riallocare un buffer di 7 byte in PAGE_SIZE + 1, credo che proverà ad allocare la successiva pagina contigua se disponibile.

Vale leggere quanto segue, se si sta sviluppando su Linux:

Per impostazione predefinita, Linux segue una strategia di allocazione della memoria ottimista. Ciò significa che quando malloc() restituisce non NULL non è garantito che la memoria sia effettivamente disponibile. Questo è davvero un bug errato . Nel caso in cui risultasse che il sistema ha esaurito la memoria, uno o più processi verranno uccisi dal famigerato OOM killer. Nel caso Linux viene impiegato in circostanze in cui sarebbe meno desiderabile perdere improvvisamente alcuni processi selezionati a caso, ed inoltre la versione del kernel è sufficientemente recente, si può disattivare questo comportamento overcommitting usando un comando come:

# echo 2 > /proc/sys/vm/overcommit_memory 

Vedi anche la directory di documentazione del kernel, i file vm/overcommit-accounting e sysctl/vm.txt.

0

FreeBSD e Mac OS X hanno la reallocf() funzione che libera il puntatore passato quando la memoria richiesta non può essere allocata (vedi man realloc).

+0

Piuttosto che usare questo, sarebbe molto più sensato scrivere semplicemente la propria funzione per farlo se si vuole veramente quel comportamento. Ma non riesco a immaginare che sia molto utile - sta buttando via dati preziosi probabili. –

Problemi correlati