|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Sep 2001
Città: Roma
Messaggi: 1944
|
[Per i guru del C] I segreti della malloc
Argomento del thread: vita, morte e miracoli dell'allocazione di memoria in C
Dopo l'interrogatorio spiego brevemente il perchè della cosa. Devo analizzare i dati provenienti dai route collector mondiali, che sono parecchiotti: una giornata = 20Gb. Dato che ogni giorno devo processare 20Gb per avere poi un output su cui lavorare, ho fatto un programma in C, abbastanza banale, dedito allo scopo. Il programma è veloce (2 ore) ma spreme la memoria: arriva a chiedere il massimo allocabile, 3,2 Gb. Diminuendo l'input, mi sono fatto il calcolo delle strutture dati allocate, in modo preciso e pedissequo, a partire dalle statistiche che il programma stesso stampa. Con poche possibilità di errore, ho scoperto che dovrei occupare poco più di 1,5 Gb, mentre alla fine la memoria arriva a 2020 Mb. Se si parte dal presupposto che puntatori non liberati ed inutili non ce ne sono, perchè tutto il programma fa 4 malloc, e sono ipercontrollate, allora il dubbio è che le free e le deallocazioni dallo stack non rilascino effettivamente la memoria, magari per problemi di frammentazione. Tenete presente che il programma alloca ad ogni iterazoine parecchi dati sullo stack delle varie funzioncine (cose del tipo char linea[MAX_LINE] e char delim[]=".,-/" per capirsi), e facendo sicuramente molte migliaia di iterazioni, se quelli non sono realmente deallocati, il problema si pone! E solo voi "guru" del C potete dirmi se è vero o no ![]()
__________________
"Oggi è una di quelle giornate in cui il sole sorge veramente per umiliarti" Chuck Palahniuk Io c'ero |
![]() |
![]() |
![]() |
#2 | |||||||
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Premesso che non sono il guru-della-funzione-malloc, vedrò di rispondere al meglio. Alcune cose che riporterò sono prese dalla pagina di 'man' della malloc su linux, dalla documentazione della libc (vedere <qui>) e dal VC++.
Quote:
La documentazione della libc dice: The address of a block returned by malloc or realloc in the GNU system is always a multiple of eight (or sixteen on 64-bit systems).VC++ dice: The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. Quote:
Quote:
Codice:
int *p1; int *p2; int *p3; p1 = (int*) malloc (sizeof (int)); p2 = (int*) malloc (sizeof (int)); p3 = (int*) malloc (sizeof (int)); printf ("p1 = %p\n", p1); printf ("p2 = %p\n", p2); printf ("p3 = %p\n", p3); free (p2); p2 = (int*) malloc (sizeof (int)); printf ("p2 = %p\n", p2); free (p1); free (p2); free (p3); p1 = 0x80496c0 p2 = 0x80496d0 p3 = 0x80496e0 p2 = 0x80496d0 Come vedi, la quarta malloc ha "ripreso" quel blocco di memoria che prima era stato liberato. Se avessi richiesto una quantità di memoria maggiore, molto probabilmente la malloc avrebbe cercato un'altra zona di memoria tale da soddisfare la richiesta. Quote:
Quote:
Nel "vecchio" DOS, dove non c'era una gestione della memoria virtuale, si poteva frammentare la memoria fisica (e non c'era molto da fare ...). Nei sistemi moderni con gestione della memoria virtuale, la frammentazione della memoria fisica non c'è più. La memoria fisica viene suddivisa in N pagine della stessa dimensione (es. 4KB) e il gestore della memoria virtuale può anche usare poca memoria fisica dando però l'impressione al sistema di avere molta memoria virtuale (-> swapping su disco). Quello che si può ancora frammentare è lo spazio di memoria "lineare" che ogni processo "vede". Quote:
Quote:
void *realloc(void *ptr, size_t size);Dice che può essere differente. Ma proprio alle 21.00 di una calda notte di Luglio ti devi porre queste domande esistenziali sulla malloc?? ![]() ![]()
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
|||||||
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Sep 2001
Città: Roma
Messaggi: 1944
|
Quote:
![]() Grazie delle risposte, soprattutto sulla prova fatta ![]() Cmq, ieri notte mi sono messo a cercare, ed ho scoperto un mondo di cose. Tra cui il fatto che la frammentazione è un serio problema, e ci sono delle linee guida per tentare di limitarlo. Ed inoltre, lo sapevate che esistono i garbage collector per C? ![]()
__________________
"Oggi è una di quelle giornate in cui il sole sorge veramente per umiliarti" Chuck Palahniuk Io c'ero |
|
![]() |
![]() |
![]() |
#4 | |
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
Codice:
char *p1, *p2, *p3; p1 = (char*) malloc (100); p2 = (char*) malloc (100); p3 = (char*) malloc (100); printf ("p1 = %p\n", p1); printf ("p2 = %p\n", p2); printf ("p3 = %p\n", p3); printf ("\n"); free (p2); p2 = (char*) malloc (50); printf ("p2 = %p\n", p2); printf ("\n"); p2 = (char*) realloc (p2, 70); printf ("p2 = %p\n", p2); printf ("\n"); p2 = (char*) realloc (p2, 200); printf ("p2 = %p\n", p2); printf ("\n"); free (p1); free (p2); free (p3); p1 = 0x8049798 p2 = 0x8049800 p3 = 0x8049868 p2 = 0x8049800 p2 = 0x8049800 p2 = 0x80498d0 Le prime 3 malloc allocano 3 blocchi consecutivi da 100 byte (ci può essere dello spazio in più occupato per i motivi già detti). p2 viene poi liberato; viene poi riallocato uno spazio di 50 byte e dato che ci sta in quello spazio vuoto di 100 byte, si riottiene lo stesso indirizzo di prima. La prima realloc rialloca lo spazio a 70 byte e visto che "ci sta" ancora, si riottiene nuovamente lo stesso indirizzo. La seconda realloc alloca 200 byte e visto che quello spazio di prima non è più sufficiente, va ad allocare memoria nello spazio successivo ai blocchi. Da qui si vede bene che la realloc può restituire un nuovo puntatore oppure anche lo stesso. ![]()
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
|
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Jun 2006
Città: Inverno: Novgorod. Estate: Haifa
Messaggi: 879
|
Quote:
__________________
Hosti non solum dandam esse viam ad fugiendum, sed etiam muniendam / Ceterum censeo Carthaginem esse delendam / Et facere et pati fortia romanum est / Nemo Romanorum pacis mentionem habere dignatus est / Roma locuta, causa finita Milla |
|
![]() |
![]() |
![]() |
#6 | ||||||||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Fermo restando che queste domande non sono specifiche per il c:
Quote:
In genere le librerie gestiscono un proprio heap, dinamicamente espandibile, che contiene aree di indirizzi virtuali (non necessariamente memoria fisica!!) forniti dal s/o. All'interno dell'heap, viene implementato un altro sistema di allocazione e gestione della frammentazione. A volte vengono allocate altre regioni oltre l'heap principale. Il buddy allocator è solo un algoritmo di gestione dei blocchi liberi; lo usa il kernel linux internamente (e su questo implementa altri allocatori), non so quale sia l'algoritmo utilizzato dalle libc. Quote:
Quote:
Visto che le allocazioni sono piccole, probabilmente ti troverai con un "buco" di 4 byte nell'heap, pronto per le allocazioni successive. Quote:
1) brk() 2) mmap(MAP_ANONYMOUS) Vengono invocate automaticamente dalle libc quando necessario. Non azzardarti a toccare brk manualmente. Una mmap esplicita può essere utile se devi allocare un blocco enorme di indirizzi _virtuali_ (continuo fino alla nausea a ripetere che sono diversi dalla memoria fisicamente assegnata al programma); le libc dovrebbero però fare lo stesso in questo caso. Quote:
Quote:
Quote:
La documentazione mi sembra chiara. Quote:
Nota che lo stack non gioca alcun ruolo nella frammentazione. Preoccupati degli indirizzi virtuali occupati dal programma; cat /proc/<pid>/maps ti aiuta.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
||||||||
![]() |
![]() |
![]() |
#7 | |||||||||||||
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
![]() spiegati... Quote:
Quote:
Quote:
Quote:
Quote:
e comunque su qualsiasi sistema Intel con paginazione, la deallocazione dallo stack non ti fa guadagnare spazio finché non scendi sotto il prossimo page bound, e su molte implementazioni non te ne fa guadagnare comunque. la dimensione dello stack è sempre un multiplo di 0x1000. Ultima modifica di 71104 : 29-07-2006 alle 17:53. |
|||||||||||||
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Feb 2001
Messaggi: 824
|
[OT, sono un amico di scoperchiatore]
e comprati sti 4 giga di ram, a purciaro! ![]() ![]() ![]() [/fine OT]
__________________
Il Poeta assomiglia a questo principe // Dei nembi, che frequenta la tempesta // E ride dell'arciere; a lui, esiliato // Sulla terra, fra gli schiamazzi, le ali // Da gigante impediscono il cammino. (Baudelaire - l'albatro) |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 17:28.