PDA

View Full Version : La memoria


misterx
13-10-2002, 19:38
Cionci, guarda questo scorcio di programma che ad ogni passaggio
crea un nuovo spazio in memoria atto a contenere un'immagine, nel
programma ne vengono caricate ben 100!

Come gestisca ogni singolo puntatore alle singole immagini mi è oscuro
ma la mia domanda è la seguente:

possibile che con una semplice chiamata: delete MyImage la
memoria allocata dalle 100 immagini viene deallocata tutta in un colpo
solo?

Usando le API di windows, sembrerebbe di si: occhio, ho usato il condizionale
in quanto non ne sono affatto sicuro perchè: uscendo dal programma e rilanciando
il medesimo più volte, la memoria totale fisica di sistema continua incessantemente
a diminuire

a te l'ardua sentenza:)

TImage *MyImage = new TImage(Form1);

for (int i =0; i <100; i++)
{

Image = new TImage(this);

MyImage->Picture->LoadFromFile(FileListBox1->Items->Strings[i])

}
delete MyImage;

cionci
14-10-2002, 09:15
Image = new TImage(this);

Ma questo quando lo deallochi ?

misterx
14-10-2002, 09:47
mai, e qui sta il punto

prima di caricare le 100 immagini visualizzo la memoria disponibile con:
_MEMORYSTATUS lp_membuf;

GlobalMemoryStatus(&lp_membuf);
StatusBar1->Panels->Items[1]->Text = (int)lp_membuf.dwAvailPhys;



e dopo aver caricato le 100 immagini richiamo:

_MEMORYSTATUS lp_membuf;

GlobalMemoryStatus(&lp_membuf);
StatusBar1->Panels->Items[1]->Text = (int)lp_membuf.dwAvailPhys;


e calcolo la differenza che è sempre zero: questo non mi spiego

possibile che chiamando il delete una sola volta e fuori dal loop venga deallocata tutta la memoria?

cionci
14-10-2002, 10:16
No...però ci potrebbero essere meccanismi interni del BCB che fanno questo in automatico...

misterx
14-10-2002, 19:25
ho approfondito ed è tutto clamorosamente cannato il mio ragionamento perchè con:

delete MyImage

fuori dal loop, viene cancellata solo l'ultima allocazione; le funzioni di gestione della memoria ritornano zero perchè l'indirizzo delle precedenti allocazioni viene perso per sempre: memory leak

morale: BCB non dealloca automaticamente

grazie cionci in ogni caso:)

misterx
14-10-2002, 19:39
pensa che se io scrivo:


TForm *Form2 = new TForm(this);
TImage *MyImage = new TImage(Form2);

for (int i =0; i <100; i++)
{
Image = new TImage(Form2);
MyImage->Picture->LoadFromFile(FileListBox1->Items->Strings[i])
}

ed ora scrivo

delete Form2;

viene cancellato tutto quanto allocato in un colpo solo; una caratteristica di BCB

misterx
16-10-2002, 19:54
come non detto, i problemi di memoria continuano

sapete se la memoria virtuale in windows è gestita automaticamente?

grazie :)

cionci
17-10-2002, 07:49
Originariamente inviato da misterx
[B]sapete se la memoria virtuale in windows è gestita automaticamente?

In che senso ? Se è memoria virtuale DEVE essere gestita automaticamente per definizione :)

Non capisco ancora bene il tuo codice...
Qaul'è l'oggetto che deve avere 100 istanze ?

misterx
17-10-2002, 08:55
Originariamente inviato da cionci
[B]
In che senso ? Se è memoria virtuale DEVE essere gestita automaticamente per definizione :)

Non capisco ancora bene il tuo codice...
Qaul'è l'oggetto che deve avere 100 istanze ?


in questo senso

se tu compili il codice da me postato e lo utilizzi per visualizzare su un form 1500 immagini ad esempio; ti accorgerai che ad un certo punto verranno emessi dei messaggi di errore alquanto depistanti del tipo: "Canvas does not allow"

questo mi ha fatto pensare che il codice da me postato utilizzi solo la ram fisica di sistema a meno che non si informi windows di ciò attraverso opportune funzioni

anch'io ho sempre pensato che la memoria virtuale fosse gestita da windows in modo automatico ma gli strani messaggi e bada bene, non ripetibili, mi hanno depistato

per questo chiedevo conferme:)

Angus
17-10-2002, 09:38
Mi ricordo che nessuno si preoccupa di deallocare niente (al contrario del GarbageCollector Java per esempio).
Quindi ad ogni new qualcosa dovrebbe corrispondere un delete quel qualcosa. A meno che non si cancellino oggetti che hanno figli, ossia oggetti che avevano come parent o owner o qualcosa simile l'oggetto cancellato.
Sono solo ricordi offuscati dal tempo passato da quando smanettavo col bcb... ah bei tempi!!! Quindi ditemi se ho sparato troppo grosso :D

cionci
17-10-2002, 11:40
Ma quei 100 TImage quando li deallochi ??!?!?!

misterx
17-10-2002, 12:08
x Angus

tutto vero quanto hai detto


x Cionci

li dealloco solo al termine della visualizzazione, se li deallochi prima, non li visualizzi più

cionci
17-10-2002, 12:10
Originariamente inviato da misterx
[B]li dealloco solo al termine della visualizzazione, se li deallochi prima, non li visualizzi più
Ma ne deallochi solo uno perchè tutte le volte con new perdi il puntatore a quello precedente... Ecco dov'è il memory leak...

misterx
17-10-2002, 12:31
hai ragione ma, BCB offre anche questo che dovrebbe ricatturare il vecchio puntatore; almeno credo sia così:



for(int i=0; i < Form2->ComponentCount;i++)
if(Form2->Components[i]->ClassNameIs("TImage"))
{
TImage *img = (TImage*)Form2->Components[i];
delete img;
}

Angus
17-10-2002, 13:35
Originariamente inviato da misterx
[B]hai ragione ma, BCB offre anche questo che dovrebbe ricatturare il vecchio puntatore; almeno credo sia così:



for(int i=0; i < Form2->ComponentCount;i++)
if(Form2->Components[i]->ClassNameIs("TImage"))
{
TImage *img = (TImage*)Form2->Components[i];
delete img;
}

ogni qual volta trovi un TImage e lo deallochi, sei sicuro che il vettore Form2->Components rimanga invariato? E se invece cambiasse ogni volta come pure il valore di ComponentCount?
Per essere sicuro in entrambi i casi potresti scrivere il codice in modo da mettere prima i riferimenti ai TImage in un vettore temporaneo e poi ciclare su quello.

misterx
17-10-2002, 13:55
Originariamente inviato da Angus
[B]

ogni qual volta trovi un TImage e lo deallochi, sei sicuro che il vettore Form2->Components rimanga invariato? E se invece cambiasse ogni volta come pure il valore di ComponentCount?
Per essere sicuro in entrambi i casi potresti scrivere il codice in modo da mettere prima i riferimenti ai TImage in un vettore temporaneo e poi ciclare su quello.


ho fatto delle prove e ad ogni TImage allocato ho salvato il puntatore su file

quando dealloco, salvo nuovamente su file il puntatore di ogni TImage ritornato dalla:

TImage *img = (TImage*)Form2->Components[i];

sino ad ora, dopo numerose prove, sono sempre i medesimi indirizzi


la morale è che preferisco scrivere questo:

TImage *MyImage;
MyImage = new TImage(Form2);

in luogo di questo:

TImage *MyImage[100];

in quanto, con la prima, alloco memoria in modo dinamico


faccio in questo modo perchè non vorrei sprecare prezioso spazio nella memoria stack

BCB, se non ricordo male, ha di default 2 valori per l'area stack:

min=4Kb
max=100Kb

ma quando compilo non so se crea automaticamente lo spazio necessario per tutte le variabili ed i vettori

qualcuno mi ha detto che in teoria potrei scrivere anche:

TImage *MyImage[1000000]; (un milione) di puntatori di tipo (TImage da 4 byte per puntatore), in quanto è esclusivamente in funzione della memoria del PC

però così facendo sprecherei preziosa memoria

mi ricordo che in turbo C, l'area stack doveva essere impostata con: __stklen(......) o similare


se ho scritto qualche cavolata correggetemi pure:)

Angus
17-10-2002, 16:13
Originariamente inviato da misterx
[B]

ho fatto delle prove e ad ogni TImage allocato ho salvato il puntatore su file

quando dealloco, salvo nuovamente su file il puntatore di ogni TImage ritornato dalla:

TImage *img = (TImage*)Form2->Components[i];

sino ad ora, dopo numerose prove, sono sempre i medesimi indirizzi


Questo farebbe pensare che il vettore Components non tenga conto di quello che gli succede sotto il <vl0... mi spiego: all'inizio il vettore contiene 10 componenti, io ne posso deallocare alcuni e lui continua a dirmi che i componenti sono 10?!? Se così fosse... ROBE DA PAZZI!!!

misterx
17-10-2002, 16:33
Originariamente inviato da Angus
[B]

Questo farebbe pensare che il vettore Components non tenga conto di quello che gli succede sotto il <vl0... mi spiego: all'inizio il vettore contiene 10 componenti, io ne posso deallocare alcuni e lui continua a dirmi che i componenti sono 10?!? Se così fosse... ROBE DA PAZZI!!!


Ho già sperimentato anche questo ed il numero di componenti ritornati è sempre quello corretto.

Stranamente, facendo girare il programma sotto win2k non si hanno i benchè minimi problemi.

Il programma che sto sviluppando, per darti un'idea, è una sorta di ACDSee

cionci
17-10-2002, 16:39
Originariamente inviato da misterx
[B]Il programma che sto sviluppando, per darti un'idea, è una sorta di ACDSee
Chissà perchè me lo ero immaginato ;)

Angus
17-10-2002, 17:04
Originariamente inviato da misterx
[B]

Ho già sperimentato anche questo ed il numero di componenti ritornati è sempre quello corretto.



Cosa intendi per sempre corretto?
Se intendi dire che deallocando un componente il numero dei componenti totali diminuisce di uno, mi domando se quel ciclo for ti vada a pescare TUTTI i TImage. Mi spiego:

Array Components: [Oggetto, TImage, TImage, Oggetto]
ComponentCount = 4;
quando i == 1 cancello il primo TImage.
A questo punto come è fatto Components?

Se fosse così:
[Oggetto, TImage, Oggetto]
ComponentCount = 3;
allora i++ ti porterebbe a saltare un TImage...

Se invece fosse cosà:
[Oggetto, NULL, TImage, Oggetto]
allora li beccheresti tutti.

MAH!

ps: vado a casa, a domani!

cionci
17-10-2002, 17:07
Infatti lui controlla che sia un TImage prima di cancellarlo...

Angus
17-10-2002, 17:10
Originariamente inviato da cionci
[B]Infatti lui controlla che sia un TImage prima di cancellarlo...

Non intendevo dire che avrebbe potuto cancellare qualcos'altro, ma che non beccherebbe TUTTI i TImage per poterli poi cancellare.

ps: ma io non dovevo essere già fuori per strada sulla via di casa?!? MAH!

cionci
17-10-2002, 17:17
E perchè ? Se si scorre tutti i componenti presenti nel form li trova tutti...

Se noti il puntatore al form viene passato come parametro al costruttore di TImage...
In questo modo il costruttore di TImage va a modificare il vettore dei componenti aggiungendo il suo puntatore come ultimo elemento...

misterx
17-10-2002, 20:11
Originariamente inviato da cionci
[B]
Chissà perchè me lo ero immaginato ;)


sai, più uso BCB e più mi accorgo che è meno giocattolo di quanto pensassi all'inizio in quanto, puoi decidere di scrivere codice nel modo che più ti aggrada

Ad esempio, ACDSee, mi pare usi una ImageList, componente già bello e pronto per visualizzare le immagini sotto forma di diapositive ma.....

se si continua ad usare cmponenti già belli e pronti ben poco si impara di C/C++

e siccome amo reinventare l'H2O calda, me ne costruisco uno io, sopportandone tutti gli errori del caso:)

misterx
17-10-2002, 20:17
Originariamente inviato da Angus
[B]

Se intendi dire che deallocando un componente il numero dei componenti totali diminuisce di uno, mi domando se quel ciclo for ti vada a pescare TUTTI i TImage.



è proprio come sostieni tu:) infatti se nascondi una TImage usando:

......Visible = false

e scorri col ciclo le immagini per conoscere quante sono visibili e quante invisibili, viene ritornato sempre il numero corretto in quanto io chiedo

if(...... == TImage) fai qualcosa

altrimenti

vai oltre

ti assicuro che anche senza vettori BCB rintraccia l'indirizzo corretto e dealloca correttamente la memoria; molto probabilmente è legato a quanto dicevi tu "Owner -> Parent"

Magari tiene una lista in automatico dei puntatori ai singoli Parent:)

misterx
17-10-2002, 20:17
Originariamente inviato da Angus
[B]

Se intendi dire che deallocando un componente il numero dei componenti totali diminuisce di uno, mi domando se quel ciclo for ti vada a pescare TUTTI i TImage.



è proprio come sostieni tu:) infatti se nascondi una TImage usando:

......Visible = false

e scorri col ciclo le immagini per conoscere quante sono visibili e quante invisibili, viene ritornato sempre il numero corretto in quanto io chiedo

if(...... == TImage) fai qualcosa

altrimenti

vai oltre

ti assicuro che anche senza vettori BCB rintraccia l'indirizzo corretto e dealloca correttamente la memoria; molto probabilmente è legato a quanto dicevi tu "Owner -> Parent"

Magari tiene una lista in automatico di puntatori ai singoli Parent:)

Angus
18-10-2002, 09:32
Originariamente inviato da cionci
[B]E perchè ? Se si scorre tutti i componenti presenti nel form li trova tutti...

Se noti il puntatore al form viene passato come parametro al costruttore di TImage...
In questo modo il costruttore di TImage va a modificare il vettore dei componenti aggiungendo il suo puntatore come ultimo elemento...

forse non mi sono spiegato bene... innanzitutto la frase:
E perchè ? Se si scorre tutti i componenti presenti nel form li trova tutti... è sempre vera se e solo se è vera la supposizione, e cioè Se si scorre tutti i componenti presenti nel form, ed è proprio questo che sto mettendo in discussione.
Per quanto riguarda In questo modo il costruttore di TImage va a modificare il vettore dei componenti aggiungendo il suo puntatore come ultimo elemento... mi sono semplicemente chiesto se anche il distruttore di TImage non vada a combinare qualcosa su quel vettore...
Sinceramente non mi spiego come faccia quel ciclo a scorrere tutto il vettore se questo contiene alcuni NULL che ne vanno a gonfiare la dimensione... perchè se ComponentCount viene incrementato dal costruttore di TImage e decrementato dal suo distruttore, non c'è più corrispondenza tra la lunghezza del vettore e il valore di ComponentCount, a meno che non venga ricostruito il vettore... Ripeto MAH!

cionci
18-10-2002, 09:43
Beh...in effetti...ora che mi ci fai ripensare...
Se il vettore viene ricompattato dal distruttore facendo i++ si salta un oggetto...

Ma può essere anche che il valore di componentCount non cambi chiamando il distruttore e magari nella posizione relativa del vettore ci viene messo NULL...
In questo modo funziona tutto...

Angus
18-10-2002, 09:55
Originariamente inviato da cionci
[B]Beh...in effetti...ora che mi ci fai ripensare...
Se il vettore viene ricompattato dal distruttore facendo i++ si salta un oggetto...

Ma può essere anche che il valore di componentCount non cambi chiamando il distruttore e magari nella posizione relativa del vettore ci viene messo NULL...
In questo modo funziona tutto...

...cominciavo a pensare di non ricordare proprio una ceppa di c++...
comunque se il valore di ComponentCount non cambia e tantomeno il vettore Components[]... beh ci credo che dopo qualche migliaio di TImage creati e poi distrutti si abbiano problemi di memoria... immagino un vettore con tanti bei puntatori a NULL inutili il cui numero cresce sempre di più, andando a gonfiare tutto, pure il ciclo for!!!

Angus
18-10-2002, 10:02
Originariamente inviato da Angus
[B]

...cominciavo a pensare di non ricordare proprio una ceppa di c++...
comunque se il valore di ComponentCount non cambia e tantomeno il vettore Components[]... beh ci credo che dopo qualche migliaio di TImage creati e poi distrutti si abbiano problemi di memoria... immagino un vettore con tanti bei puntatori a NULL inutili il cui numero cresce sempre di più, andando a gonfiare tutto, pure il ciclo for!!!

... a meno che il costruttore di TImage non vada a rioccupare la prima posizione libera nel vettore (dove c'è il primo NULL)...

Angus
18-10-2002, 10:07
Originariamente inviato da Angus
[B]

... a meno che il costruttore di TImage non vada a rioccupare la prima posizione libera nel vettore (dove c'è il primo NULL)...

ma se Locatelli fa le cose per bene, sarebbe più opportuno immaginare che sia il costruttore sia il distruttore di TImage non facciano altro che invocare dei metodi specializzati di TForm per l'aggiunta e la sottrazione di componenti, che è improbabile facciano male il loro mestiere...

Morale della favola: 10000 parole per dire che sinceramente quel memory leak proprio non me lo spiego :D

misterx
18-10-2002, 14:01
forse ho scoperto qualcosa, ottengo errori, tra l'altro mal gestiti da windows, se supero i 16384 handle; stranezze che usa windows per tenere traccia degli oggetti di ogni programma in esecuzione

però non ho trovato una funzione che mi informi quanti handle windows stia allocando per la mia applicazione

cionci
18-10-2002, 14:22
Non è che finisce lo heap ? Che è lo spazio di memoria riservato per l'allocazione dinamica...

Prova ad usare le API GetProcessHeap e HeapSize...

misterx
18-10-2002, 14:54
grazie cionci, proverò anche quelle funzioni

sto usando MemProf per tracciare il mio programma; devo ammettere che gà solo al lancio utilizza già parecchi Handle

misterx
19-10-2002, 13:15
ho provato a caricare ben 150 immagini occupando ben 563055 Kb ed alla fine ottengo un Out Of Resource

se carico invece 1600 immgini, arrivati a circa 1400, e siccome nel mio codice ho previsto il controllo delle eccezioni, mi appare una finestra con scritto nulla al suo interno; quasi non vi fossero più handle per i caratteri da scrivere

in questa situazione, windows diventa instabile nonostante l'uso della memoria sia esiguo ma, nelle varie finestre vengono visualizzati caratteri non predefiniti da me

possibile che non vi sia un metodo per conoscere a priori quanti handle ho ancora a disposizione?

usando MemProf, ho notato che ne viene usato uno per ogni oggetto del mio programma:

1 per la form creata dinamicamente
1 per il titolo presente nel form
1 per ogni immagine posizionata nel form

non so se per gli eventi viene allocato un handle

all'inizio ne ho allocati circa una quarantina e se sommo le 1400 immagini sono ben lontano da 16384 handle che winows mette a disposizione per ogni applicazione attiva

boh?

cionci
19-10-2002, 14:08
In Windows ogni oggetto è associato ad un handle... E' anche probabile che per ogni TImage che dichiari vi sia più di un handle...

Secondo me devi passare per un'altra strada... Ad esempio disegnando le bitmap direttamente sul DC...

misterx
19-10-2002, 17:54
Originariamente inviato da cionci
[B]

Secondo me devi passare per un'altra strada... Ad esempio disegnando le bitmap direttamente sul DC...


poi diverrebbe più complesso gestire la selezione di una immagine a caso, si dovrebbe tenere traccia dlle coordinate del mouse ed in base alla sua posizione comportarsi di conseguenza

sempre che tu intendevi con "disegnando le bitmap direttamente sul DC" disegnare una mega bitmap su un form

sai, anche così non è male ma se almeno riuscissi a bloccare il mio prog prima che di un'eccezione

ho riempito il codice di

try{
.....
}
catc(...){}

per poter catturare le eccezioni e comportarmi di conseguenza, ma non c'è modo di bloccare il mio programma prima; quando avviene un'eccezzione è troppo tardi

mi sa che devo usare funzioni che giochino d'anticipo

misterx
19-10-2002, 19:49
cmq, in ultima analisi, ho provato a piazzare ben 6000 immagni su un form senza il benchè minimo problema

in pratiga viene visto come una mega bitmap

però diviene più difficile gestire il tutto se si desidera ad esempio eliminare una figura presente alle coordinate (X,Y)

ti posterò i 2 esempi così tocchi con mano le problematiche:)

grazie in tutti i casi Cionci ed Angus:)

cionci
20-10-2002, 12:08
Vai...ok...

misterx
22-10-2002, 16:39
è ancora allo stato brado; visualizza solo BMB e JPG

qui (http://digilander.libero.it/daffol/viewer.zip)

cionci
23-10-2002, 09:23
Ottimo...sei un grande :)

Manca un controllo sulla fine delle immagini (sul next) durante la visualizzazione...
Se clicko sullo sfondo della preview rende un eccezione...
Devi fare in modo che i controlli Prev e Next cambino posizione se la finestra di visualizzazione viene ridimensionata...

misterx
23-10-2002, 14:38
la vera interfaccia è questa:


http://digilander.libero.it/daffol/interf_l.jpg

cionci
23-10-2002, 14:41
Davvero complimenti :)

misterx
23-10-2002, 19:35
Originariamente inviato da cionci
[B]Davvero complimenti :)


fai il bravo che sei capace anche tu; guarda che lo so;)


cmq, sto implementando la regolazione della luminosità e contrasto nelle immagini: se ne sai già qualcosa, spara:D ;)

ho trovato questa formula:


Luminosità:
r:= round(r * ( 1 + intens/100 ));
g:=round(g * ( 1 + intens/100));
b:=round(b * ( 1 + intens/100));

contrasto:
r:= round(r + intens/100*(r-127));
g:= round(g + intens/100*(g-127));
b:= round(b + intens/100*(b-127));

misterx
23-10-2002, 20:58
cmq, l'equivalente in "C" nostrano è il seguente:

Luminiosità:

r= floor(r*Percent/100) + floor(255 - Percent/100*255);
g= floor(g*Percent/100) + floor(255 - Percent/100*255);
b= floor(b*Percent/100) + floor(255 - Percent/100*255);


dove:

(r,g,b) sono le tre componenti del colore

Percent è un valore che va da 0/100

per chi ne avesse bisogno:)

cionci
24-10-2002, 07:53
Bene...buono a sapersi ance questo :)

misterx
24-10-2002, 15:20
si ma il metodo non funziona molto bene; sarebbe bello avere il medesimo algoritmo che utilizza PhotoShop;)

misterx
24-10-2002, 19:23
dimenticavo: non è reversibile, almeno io perdo pezzi per strada in quanto se la applico non ottengo la luminostà originaria....mah


Luminiosità:

r= floor(r*Percent/100) + floor(255 - Percent/100*255);
g= floor(g*Percent/100) + floor(255 - Percent/100*255);
b= floor(b*Percent/100) + floor(255 - Percent/100*255);


ed il suo contrario:

r= floor(r*100/Percent) + floor(255 - 100/Percent*255);
g= floor(g*100/Percent) + floor(255 - 100/Percent*255);
b= floor(b*100/Percent) + floor(255 - 100/Percent*255);

cionci
24-10-2002, 22:34
Beh...è chiaro...perdi pezzi sull'arrotondamento...

misterx
25-10-2002, 09:39
eliminando floor è andato tutto a posto:)

Luminiosità:

r= (r*Percent/100) + (255 - Percent/100*255);
g= (g*Percent/100) + (255 - Percent/100*255);
b= (b*Percent/100) + (255 - Percent/100*255);


ed il suo contrario:

r= (r*100/Percent) + (255 - 100/Percent*255);
g= (g*100/Percent) + (255 - 100/Percent*255);
b= (b*100/Percent) + (255 - 100/Percent*255);