PDA

View Full Version : una domanda su: FreeLibrary(...)


misterx
28-11-2001, 15:58
Ho notato che se si scrive una funzione del tipo:


a) apri la libreria
b) se ok trova la funzione in essa
c) se trovata usa la funzione
d) quindi chiudi e libera la memoria allocata dalla libreria


bene, richiamando + volte la medesima funzione dall'interno di un'altra funzione (oops che ripetitivo) la memoria non viene liberata, come se la chiamata FreeLibrary(); non esistesse.

domanda:

vi risulta che sia Windows a comportarsi così?

ilsensine
28-11-2001, 16:52
Se la funzione di libreria alloca memoria, tu la liberi e non vedi comunque diminuire la memoria occupata dal processo, ciò può essere dovuto a una frammentazione della memoria hash del processo. La memoria rimane disponibile nell'hash, ma esso presenta parecchi "buchi liberi" (in genere più piccoli di 4k - la dimensione di una pagina di memoria) e non può quindi essere ridotto restituendo a Windows la memoria non più utilizzata. Mi è capitato una volta un problema simile, con il Delphi, e credo sia dovuto a un non perfetto riutilizzo dell'hash da parte delle librerie di gestione della memoria della VCL. Ovviamente se la funzione alloca memoria e tu ti "scordi" di liberarla è un altro discorso (questo non te lo fa la FreeLibrary :))

ilsensine
28-11-2001, 17:01
(oops per hash voledvo dire heap, ovviamente)

misterx
28-11-2001, 17:35
+ tardi posto un esempio di 2 metodi

misterx
28-11-2001, 20:38
primo esempio mangia memoria


//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (int i =0; i <FileListBox1->Items->Count; i++)
Image2->Picture->Bitmap->Handle = MyLoadPic(FileListBox1->Items->Strings[i].c_str(),false);
}
//---------------------------------------------------------------------------
HBITMAP TForm1::MyLoadPic(char *filename, bool Progressflag)
{
typedef HBITMAP (__stdcall *IMPPROC) (char *, bool);
IMPPROC ImpFunc;
HINSTANCE DllInstance;
HBITMAP ritval;

DllInstance=LoadLibrary("NViewLib.dll");
if(DllInstance != NULL){
ImpFunc =(IMPPROC) GetProcAddress(DllInstance,"NViewLibLoad");
if(ImpFunc != NULL) {
ImpFunc(filename,Progressflag);
ritval = ImpFunc(filename, Progressflag);
}
else {
ShowMessage("Funzione non trovata");
}
FreeLibrary(DllInstance);
}
else
ShowMessage("Manca la Libreria NViewLib");

return ritval;
}
//---------------------------------------------------------------------------

ilsensine
28-11-2001, 21:33
Non conosco l'oggetto HBITMAP, ma a naso direi che è un handle implementato come un puntatore all'oggetto vero e proprio o qualcosa di simile, oggetto che viene allocato dalla funzione stessa della libreria. Se è così, chi lo distrugge quando non è più necessario?
Cmq (mi sembra che stai usando il Borland) se spulci tra i metodi di TImage o classi ereditate, mi sembra di ricordare che ci sia una sorta di LoadFromFile (forse tra i metodi del TCanvas o TBitmap?)

misterx
28-11-2001, 21:35
conosco quanto mi dici ma ho bisogno di usare una DLL esterna in quanto mi permette di visualizzare una marea di formati grafici; caratteristica non presente in BCB.

ilsensine
28-11-2001, 21:49
Immaginavo
Cmq gli oggetti HBITMAP _devi_ distruggerli manualmente quando non sono più necessari con DeleteObject (ho dato un'occhiata alla guida Win32)

misterx
28-11-2001, 22:00
sob, ma se io utilizzo sempre lo stesso oggetto....

ho provato ad allocare dinamicamente TImage *Image = new.... e subito dopo a distruggerlo con delete ..... ma il risultato non cambia.

Il risultato cambia se apri la libreria una sola volta, usi la funzione di lettura quanto vuoi, quindo la chiudi.

In questo ultimo caso puoi aprire tutte le immagini che vuoi e lo spreco di memoria è minimo.

Quindi il problema è:

perchè se chiamo la funzione esternamente la memoria occupata si incrementa ad ogni ciclo del (for...)

mentre se inserisco lo stesso ciclo all'interno della funzione lo spreco di memoria non esiste?

Non è che windows con l sue maledette predizioni si rifiuta di deallocare fino a quando non esco dall'aplicazione?

ilsensine
28-11-2001, 22:13
Cioè: vuoi dire che così non hai problemi?

void __fastcall TForm1::Button1Click(TObject *Sender)
{
HINSTANCE DllInstance = LoadLibrary("NViewLib.dll");
IMPPROC ImpFunc = (IMPPROC) GetProcAddress(DllInstance,"NViewLibLoad");
for (int i =0; i <FileListBox1->Items->Count; i++)
Image2->Picture->Bitmap->Handle = ImpFunc(FileListBox1->Items->Strings[i].c_str(),false);
FreeLibrary(DllInstance);
}

misterx
28-11-2001, 22:30
azz....sei un gallo;) proprio così; riposto il codice della seconda soluzione, quella che non spende memoria solo perchè l'ho testato con successo:

l'unica differenza è che non riesco a piazzare il codice di ritorno della funzione per studiarne il valore e comportarmi di conseguenza.
Il secondo metodo qui e da te postato ha lo svantaggio che se mi serve la stessa funzione in altre parti devo riscriverla per (n) volte.

Dov'è il mistero?

se hai voglia prova, vedrai che è così......ho idea ma è solo una mia supposizione che ci sia lo zampino di windows...predizioni...mah...



//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
typedef HBITMAP (__stdcall *IMPPROC) (char *, bool);
IMPPROC ImpFunc;
HINSTANCE DllInstance;

DllInstance=LoadLibrary("resource\\NViewLib.dll");
if(DllInstance != NULL){
ImpFunc =(IMPPROC) GetProcAddress(DllInstance,"NViewLibLoad");
if(ImpFunc != NULL) {

for (int i =0; i <FileListBox1->Items->Count; i++)
Image2->Picture->Bitmap->Handle = MyLoadPic(FileListBox1->Items->Strings[i].c_str(),false);

}
else {
ShowMessage("Could not find a function");
}
FreeLibrary(DllInstance);
}
else
ShowMessage("Could not load library");
}
//---------------------------------------------------------------------------

ilsensine
28-11-2001, 22:51
Al di là di tutto, però, questa riga mi sembra dubbia:
for (int i =0; i <FileListBox1->Items->Count; i++)
Image2->Picture->Bitmap->Handle = MyLoadPic(FileListBox1->Items->Strings[i].c_str(),false);


Cioè: sovrascrivi Image2->...->Handle con FileListBox1->...->Count valori diversi...perchè?
E comunque quelli precedenti li devi deallocare con DestroyObject

misterx
28-11-2001, 22:58
no no, non dealloco nulla e funziona benisimo ma....non so perchè...

cmq, continuo a sovvrascrivere

ilsensine
29-11-2001, 08:47
Al di là di questo, alla fine del ciclo for in Image2->...->Handle ti ritrovi l'handle dell'ultima immagine caricata...e le precedenti?

misterx
29-11-2001, 09:43
no, ne rimane uno solo, almeno credo

forse ad ogni assegnamento la VCL distrugge l'oggetto automaticamente per ricrearlo ex novo solo se il loop è all'interno della funzione di apertura/chiusura della DLL


anche così non si risolve nulla:

for (int i =0; i <FileListBox1->Items->Count; i++)
{
Image = new TImage(Form1);
Image->Picture->Bitmap->Handle = MyLoadPic(FileListBox1->Items->Strings[i].c_str(),false);
delete Image;
}

misterx
29-11-2001, 10:30
correggo, l'Handle cambia ogni volta.....

ho caricato con il metodo sopra (n) immagini per un totale di 68Mb; bene, la memoria di sistema occupata al termine dell'ultima immagine era di 68Mb.....roba da matti......

possibile che anche:

TImage *Image = new ......

e poi

delete Image

non funzioni?

misterx
29-11-2001, 11:08
usando la LoadFromFile di BCB, e sovvrascrivendo, tale funzione spreca solo la memoria di una immagine alla volta.

Io mi domando come sia strutturata tale funzione....boh...

ilsensine
29-11-2001, 11:12
Mi sta sorgendo il dubbio che sovrascrivere l'Handle della Bitmap di TImage sia una procedura scorretta. Comunque prova a fare così:
{
DestroyObject(Image->Picture->Bitmap->Handle);
Image->Picture->Bitmap->Handle = MyLoadPic(filename,false);
}

misterx
29-11-2001, 12:15
niente da fare, lo spazio occupato è ancora la somma di tutte le immagini lette.

Bisognerebbe conoscere come fa LoadFromFile.


Ho provato anche così ma niente, medesimo risultato

TPicture *MyPicture;

for (int i =0; i <FileListBox1->Items->Count; i++)
{
MyPicture = new TPicture();
MyPicture->Bitmap->Handle = MyLoadPic(FileListBox1->Items->Strings[i].c_str(),false);

MyPicture->Free();

}

anche con

Image->Destroy();

nulla da fare

misterx
29-11-2001, 20:33
.

misterx
02-12-2001, 14:23
x ilsensine

se hai voglia e pazienza qui trovi due esempi scritti da me per BCB, sperando che tu possegga ancora tale compilatore.....

http://digilander.iol.it/daffol/Examples.zip

misterx
02-12-2001, 14:26
x ilsensine

se hai voglia e pazienza qui trovi due esempi scritti da me per BCB, sperando che tu possegga ancora tale compilatore.....

Il primo esempio usa LoadFromLibrary della VCL e libera tutta la memoria

Il secondo esempio usa una funzione di una DLL ma non libera la memoria

Se riesci a capirci qualcosa.....grazie 1000

http://digilander.iol.it/daffol/Examples.zip

ilsensine
02-12-2001, 19:53
Vedrò di darci una occhiata domani, poi ti faccio sapere
Ciao

misterx
02-12-2001, 20:08
rigrazie....:)

ilsensine
03-12-2001, 10:52
Niente da fare, per me ha proprio problemi la libreria che usi. Ho fatto questa semplice prova: carico una immagine con la funzione di libreria, e la distruggo subito con DeleteObject. Non creo neanche la TImage, in modo da essere sicuro che l'unica memoria allocata è quella della libreria. Risultato: memory leak.

misterx
03-12-2001, 16:08
comincio a pensare che sia un limite imposto dal produttore della DLL, beh, ma poteva anche citarlo nella documentazione; molto poco professionale.

Mi ha fatto lavorare per nulla...

misterx
03-12-2001, 20:50
ed ho idea, ilsensine che tu abbia ragione; ho scaricato per prova alcuni visualizzatori che usano tale libreria bene: manifestano tutti il medesimo problema: possibile che nessuno si sia accorto?

i soliti furbetti:D