View Full Version : La memoria
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;
Image = new TImage(this);
Ma questo quando lo deallochi ?
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?
No...però ci potrebbero essere meccanismi interni del BCB che fanno questo in automatico...
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:)
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
come non detto, i problemi di memoria continuano
sapete se la memoria virtuale in windows è gestita automaticamente?
grazie :)
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 ?
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:)
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
Ma quei 100 TImage quando li deallochi ??!?!?!
x Angus
tutto vero quanto hai detto
x Cionci
li dealloco solo al termine della visualizzazione, se li deallochi prima, non li visualizzi più
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...
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;
}
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.
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:)
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!!!
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
Originariamente inviato da misterx
[B]Il programma che sto sviluppando, per darti un'idea, è una sorta di ACDSee
Chissà perchè me lo ero immaginato ;)
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!
Infatti lui controlla che sia un TImage prima di cancellarlo...
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!
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...
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:)
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:)
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:)
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!
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...
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!!!
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)...
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
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
Non è che finisce lo heap ? Che è lo spazio di memoria riservato per l'allocazione dinamica...
Prova ad usare le API GetProcessHeap e HeapSize...
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
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?
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...
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
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:)
è ancora allo stato brado; visualizza solo BMB e JPG
qui (http://digilander.libero.it/daffol/viewer.zip)
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...
la vera interfaccia è questa:
http://digilander.libero.it/daffol/interf_l.jpg
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));
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:)
Bene...buono a sapersi ance questo :)
si ma il metodo non funziona molto bene; sarebbe bello avere il medesimo algoritmo che utilizza PhotoShop;)
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);
Beh...è chiaro...perdi pezzi sull'arrotondamento...
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);
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.