Newsgroup: it.comp.lang.c++
Titolo: STL memory pool

Usando una list<MyClass> ho necessità di cancellare gli elementi più
'vecchi' e lo faccio con una erase(begin()).
Il problema è che la memoria allocata non viene rilasciata finchè non
si raggiungono occupazioni enormi...
Ho letto che dipende dal Memory Pool STL. Come è possibile limitarne
la dimensione?
Grazie, Luc.

 la dimensione?
A livello di standard non hai modo di alterare la politica di
allocazione/rilascio di memoria di un contenitore, salvo in alcuni casi
dove puoi forzare una preallocazione di piu' elementi. Devi guardare se
il tuo compilatore fornisce delle estensioni, o cambiare contenitore.
Altrimenti una tecnica che puoi provare ad utilizzare e' scambiare il
contenuto della tua lista con una lista vuota e distruggere quella
originale. La nuova lista potrebbe contenere un po' di spazio
preallocato, ma non tutto quello degli elementi cancellati dalla
vecchia.
Ciao,
Nicola

Nicola
Grazie. Luc.

 W2000 - Task Manager
Attenzione che il problema si pone a diversi livelli. Tu puoi verificare
che il contenitore da te scelto restituisca la memoria liberata al
gestore di memoria, ma non e' affatto detto che questo la restituisca al
sistema operativo; ad esempio sotto Unix questo non e' possibile.
Ciao,
Nicola

 la dimensione?
Ho paura che non ci sia niente da fare; a meno che tu non definisca un
allocator che gestisca la memoria nella maniera che tu ritieni piu'
opportuna.  Tutti i containers della S.L. accettano un allocator nella
dichiarazione; ma francamente non ho mai provato a scriverne uno...
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it
The instructions said to use Windows 98 or better - so I installed FreeBSD.

allocazione/rilascio di memoria di un contenitore
Veramente puoi (mi risulta). Devi definire il tuo allocatore, e non
usare quello di default.
++++
Nel 99% dei casi mi sembra un ottimo modo per tirarsi la zappa sui
piedi passare per quella strada.
-- 
Tieni per te il Papero se vuoi la mia email
Sito Papero -> 
http://utenti.tripod.it/papero

piedi passare per quella strada.
Io ho visto che g++ non usa "operator new" e "operator new[]" per
allocare la memoria necessaria nei container standard.
E' qualcosa di previsto ?
Io ci sono cascato con il mio allocatore di debug in cui gli spazi
allocati dai container sembravano provenire dal nulla.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Ho paura che non ci sia niente da fare;
E' una vergogna... ma a che ca**o pensavano quando implementavano i
metodi di erase()??????
Luc.

 allocati dai container sembravano provenire dal nulla.
...cio' non toglie che se lo sostuituisci il contenitore deve poi usare
il tuo!
Ciao,
Nicola

 metodi di erase()??????
L'STL privilegia praticamente sempre l'ottimizzazione del tempo rispetto
allo spazio. Leggi il mio altro messaggio a proposito di come si fa di
solito.
Ciao,
Nicola



L'ho letto, certo, ho già iniziato a testare il metodo ma mi fa un po
senso programmare cosi 8)
Luc.
PS: fra un po mi sa che cambio container...

il tuo!
Se voglio fare un gestore di debug allora tutte le allocazioni
devono passare per quel codice... sarebbe bello se si potesse
fare senza dover scrivere codice strano in ogni punto del
programma in cui si alloca o dealloca memoria o si istanziano
container standard.
Fra l'altro la sintassi "C" si prestava molto meglio a questa
cosa almeno sul codice utente... con una banale macro si poteva
installare l'allocatore di debug...
   #define malloc(x) debug_malloc(__FILE__,__LINE__,(x))
questa cosa con la sintassi di new del C++ e' una mezza rogna :(


 metodi di erase()??????
A fare in modo che fossero ottimizzati per la velocità. Sia l'allocazione che la
deallocazione sono speed-optimized, il che vuole dire che la memoria viene
allocata a blocchi di una certa dimensione (non troppo piccoli) e poi gestita
localmente senza mai restituirla al gestore di memoria superiore.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 Lo sto testando, ma non vedo risultati, per ora...
Non certo con gli allocator standard di dinkumware!


 allocati dai container sembravano provenire dal nulla.
Cosa intendi con "alllocatore di debug" ? Se intendi dire che passi un dato
allocator fatto apposta per il debug, non dovresti avere sorprese. Se invece
intendi dire che usi un heap-manager diverso da quello della libreria standard,
salvo verificare che new/delete chiamino questo o che chiamino malloc/free e
queste a loro volta chiamino il tuo heap manager, potresti avere delle sorprese:
l'allocator di default normalmente alloca raw memory e poi usa placement
new/delete. Inoltre in alcune implementazioni gestisce un suo "heap" locale,
quindi non c'e' corrispondenza fra la quantità di dati allocata/liberata dai
container (dal punto di vista dell'utente) e le chiamate all'heap manager di
default (esattamente come non e' detto che ogni malloc arrivi all'OS!).



Mi sa che ti servirà a poco anche cambiare container!


 questa cosa con la sintassi di new del C++ e' una mezza rogna :(
Per le allocazioni che fai tu puoi sempre scrivere
#define new new(__FILE__,__LINE__)
e overloadare l'operator new!
Ovviamente questo non ti risolve le allocazioni fatte dalle librerie e potrebbe
darti qualche problema se usi dei placement new (o dei template che lo usano!).
Ma nota che anche in C non potevi ridefinire le chiamate della libreria con la
tua macro!
In C c'erano pochi casi: malloc, calloc, realloc, e librerie (che non allocavano
molto!).
In C++ effettivamente e' più complessa: hai potenzialmente un numero infinito di
new e malloc che possono essere overloadati.
Partiamo dal presupposto che il tuo codice lo scrivi tu, la cosa piu' semplice
e' scrivere New invece di new e poi usare una macro come quella scritta sopra.
Per la libreria, la maggior parte delle allocazioni si distinguono fra placement
new/delete e chiamate al vero new/delete.
Le seconde dovrebbero essere tutte fatte dall'allocator. Quindi ti basta
riscrivere le dichiarazioni dei container in modo da definire un'allocator che è
una macro e poi scrivere il tuo allocator di debug.
In questo modo risolvi quasi tutto. L'unica cosa che non puoi fare e' "inserire"
il gestore di debug su codice esistente: puoi usare una macro per "switchare"
fra debug e release ma non per modificare il codice in modo da "inserire" gli
allocator. Questo e' un discorso di sintassi dei template.
Pero' non dovrebbe essere troppo difficile "modificare" il codice tramite un
grep o perl.
Una volta modificato ... lavori con la macro.


Mi sa che ti servirà a poco anche cambiare container!
Quelli MFC funzionerebbero... però aspetto prima di fare questa
modifica che non piace neanche a me...
Luc.

vengono restituiti all'OS alla fine del programma.
Uso SGI STL 3.2. La memoria non viene rilasciata ma neanche ri-usata.
<PSEUDO CODE>
push_back(elemento);
n_elementi++;
while (n_elementi>max_dim)
  erase(begin())
  n_elementi--
</PSEUDO CODE>
perchè la push_back non usa la memoria rilasciata dalla precedente
chiamata alla funzione che ha effettuato un erase(begin())???
Luc.

 modifica che non piace neanche a me...
Vero. Ma usare la MFC non significa cambiare container, significa cambiare
libreria. Cambiare container, per me, significa, ad esempio, usare vector invece
di list.
Prima di cambiare libreria, valuta l'ipotesi di cambiare implementazione della
libreria. Ovvero resta in STL ma invece che dinkumware usa un'altra
implementazione (per esempio STLPort. Non l'ho testata ma mi dicono che
funziona).


"Luc" <TOGL...@katamail.com-TOGLI> wrote in message
news:28eeatg35e7rgccq4...@4ax.com...

Non ho capito bene che cosa fai e neppure come fai a dire che la memoria non
viene riutilizzata. Comunque, che io sappia, solo l'implementazione di
dinkumware (non la SGI) si rifiuta di disallocare la memoria.


dinkumware (non la SGI) si rifiuta di disallocare la memoria.
Ciclo
- Aggiungo un elemento ad una lista.
- Se la lista contiene troppi elementi cancello quelli piů vecchi.
Fine Ciclo
La memoria utilizzata continua a crescere fino al raggiungimento della
totale (o quasi) memoria fisica. A questo punto si genera
automaticamente un flush che riporta i consumi di memoria a livelli
molto piů bassi.
Luc.

 molto più bassi.
Non ho capito su quale sistema questo avviene ne come fai a sapere che la
memoria utilizzata cresce e poi avviene un flush.
Apparentemente quello che il tuo codice fa e' allocare e rilasciare la memoria
ogni volta. Poi c'e' un gestore di memoria (che non sembra essere quello della
STL) che ottimizza le allocazioni/disallocazioni. Puo' essere l'implementazione
di malloc/free oppure addirittura l'implementazione stessa del SO.
Per esempio: allochi quasi tutta la memoria e poi la liberi. Questa resta
allocata e verrà "flushata" solo se ne allochi ulteriore superando le dimensioni
della RAM. Ma tu non lo fai. Viceversa "fermi" il programma in attesa di input
(getch() per esempio) e a questo punto lanci un altro processo che ha bisogno di
ram.
Cosa succede? Se viene generato un flush per liberare la memoria per l'altro
processo, allora certamente e' il SO. Se invece non viene liberata, prova a far
lasciare attivo ripartire il secondo processo e a far ripartire il primo
facendogli eseguire qualche decina o centinaio di allocazioni (abbastanza da
coprire, diciamo, qualche centinaio di Kb). Se il flush avviene a questo punto
allora sono le malloc/free e probabilmente la cosa avviene anche se non usi la
STL.


di malloc/free oppure addirittura l'implementazione stessa del SO.
Gulp! 8)

"Luc" <TOGL...@katamail.com-TOGLI> wrote in message
news:96jhat0h7up6d0be7...@4ax.com...

Se trovo il tempo, nel weekend faccio qualche indagine e poi ti so dire.
Confermami: Win2K Professional + VC7 con STL della dinkumware. Specificatamente
la classe list<>.


la classe list<>.
W2000 Server + VC6 SP4 + STL SGI 3.2 + classe list<>
Luc.

 W2000 Server + VC6 SP4 + STL SGI 3.2 + classe list<>
Mi manca l'SGI. Vedremo.


applicazioni/servizi.
E perche' no? E' memoria virtuale, non memoria reale. Se non ne usi
molta (diciamo qualche decina di mega in totale) gli effetti saranno
minimali sul resto degli applicativi.


Luc,
Ho fatto qualche prova con VC6 sotto Win2K Pro senza usare nessuna STL. Usando
semplicemente le new/delete.
Ti confermo che il comportamento che descrivevi non mi pare da imputare ne a
new/delete ne al sistema operativo.
Quindi se fossi in te proverei a vedere come e' fatto l'allocator delle tue STL
(eventualmente puoi personalizzarlo).
Per i valori di memoria usati dal processo, cosi' come visti da Win, puoi usare
il tab centrale (processes) del task manager attivando tutte e cinque le colonne
relative alla memoria (Mem Usage, Peak Mem Usage, VM Size, Paged Pool, NP Pool).


Secondo me questo atteggiamento da parte degli implementatori si spiega
in base a due ragionamenti: primo, la memoria viene attribuita ai vari
processi in pagine, ed e' improbabile che vengano liberate pagine esatte
nel corso dell'esecuzione, a meno di non compiere costose
riorganizzazioni; secondo, ci si aspetta (ed almeno su Unix e' cosi')
che il sistema operativo metta in atto una politica di paging che poco
per volta porta in area di swap le pagine di memoria meno utilizzate: se
non saranno piu' riferite non dovranno essere copiate di nuovo.
Ciao,
Nicola

 wrote in message
news:3AAC91B1...@divalsim.it...

Si, ma da come mi descriveva la cosa, lui operava per pushback e popfront.
Quindi in teoria non dovrebbe essere un problema. In ogni caso mi sembra di
capire che nel suo caso specifico ci fossero MOLTISSIME
allocazioni/deallocazioni degli elementi della lista. Al punto che una
percentuale significativa della RAM veniva comunque allocata. In casi come
questi credo sia comunque buona prassi sviluppare un allocator apposta che
migliori non solo la velocità di allocazione/deallocazione ma anche la località
degli indirizzi usati dalla lista, migliorando quindi non solo il paging ma
anche il memory caching da parte del processore.


anche il memory caching da parte del processore.
Io voglio che la memoria massima usata sia quella minima a contenere N
elementi + 1.
In settimana farò altri test...
Luc.

 elementi + 1.
Fatti un allocator che alloca memoria per N+1 elementi "upfront". Userai
esattamente quella. Ne più ne meno.
Oppure fatti un allocator che alloca una frazione intera di N+1 elementi a
blocchi "on demand".


blocchi "on demand".
Mai visto/fatto un allocator (e in realtà non avrei tempo da perdere
con queste cose...). Qualche posto per reperire info?
Luc.

 esattamente quella. Ne più ne meno.
Si, se con N si intende l'espansione massima della lista, no se si
intende il numero di elementi correnti, presumibilmente minore del
massimo. In questo secondo caso deve lavorare a livello molto piu'
basso, ovvero manipolare le pagine direttamente.
Ciao,
Nicola

 con queste cose...). Qualche posto per reperire info?
La documentazione della tua STL!!


 wrote in message
news:3AACC644...@divalsim.it...

Vero. Ma in questo caso, probabilmente, scoprirà che non e' possibile a meno che
la dimensione di un elemento non corrisponda a quella di una pagina. E comunque
una allocazione direttamente da OS e' terribilmente lenta. In ogni caso anche
questo può essere fatto tramite un allocator.


La documentazione della tua STL!!
Oops... vista.
Luc.