Ciao a tutti,
ho un programma che mi sta creando dei problemi di memoria ... RAM.
Provo a spiegare il giro:
- il programma lavora con i thread (8 in contemporanea)
- in ogni thread, usando l'oggetto "TUnZipper" del sorgente "zipper.pp" di FPC, in particolare la proprietà "OnDoneStream" estraggo da un file compresso un file e lo salvo in uno stream
il codice incriminato è questo:
procedure TUnZipSingoloFile.DoDoneOutZipStreamSuStream(Sender: TObject; var aStream: TStream; AItem: TFullZipFileEntry);
begin
aStream.Position:=0;
WrkStreamOut.LoadFromStream(aStream);
//Se arriva fin qui, l'estrazione è andata a buon fine
VFUnZipOk:=True;
//Adesso posso pulire lo stream
FreeAndNil(aStream);
end;
Se quando lancio il programma, arriva ad estrarre in contemporanea su più thread dei files di grosse dimensioni (circa 100 mega l'uno), ho degli errori di "out of memory".
Ora, tenendo conto del codice che ho postato qui sopra, credo che da quando ha appena finito di eseguire la "LoadFromStream", fino a quando non ha eseguito la "FreeAndNil(aStream);", ho in memoria 2 copie dello stesso stream (di circa 100 mega), è corretto?
Se è così, c'è modo di ottimizzare la cosa, per evitare di fare una "copia", anche se per pochi millisecondi, ma di passare direttamente il contenuto da uno stream all'altro ??
Spero di essermi spiegato ...
Grazie in anticipo, Mario
La prima cosa che mi sento di suggerirti è di sostituire il
FreeAndNil(aStream);
Ho sempre usato FreeAndNil, perché il suo sorgente è questo:
procedure FreeAndNil(var obj);
var
temp: tobject;
begin
temp:=tobject(obj);
pointer(obj):=nil;
temp.free;
end;
ed ho sempre pensato che fosse la stessa cosa ... anzi meglio, perché con un'unica istruzione gli facevo eseguire le 2 cose contemporaneamente. Sbaglio io ?
In secondo luogo in casi un po' fumosi come questo conviene sempre creare un esempio che riproduce l'errore in modo che possiamo aiutarti correttamente senza buttare via tanto tempo.
In realtà, di tutta la pappardella scritta nel primo post, l'unica cosa che mi interessa al momento è questa:
Ora, tenendo conto del codice che ho postato qui sopra, credo che da quando ha appena finito di eseguire la "LoadFromStream", fino a quando non ha eseguito la "FreeAndNil(aStream);", ho in memoria 2 copie dello stesso stream (di circa 100 mega), è corretto?
Se è così, c'è modo di ottimizzare la cosa, per evitare di fare una "copia", anche se per pochi millisecondi, ma di passare direttamente il contenuto da uno stream all'altro ??
Ciao, Mario
Bonmario,hai rimosso il "override" dai tuoi distruttori?procedure TObject.Free;
begin
// the call via self avoids a warning
if self<>nil then
self.destroy;
end;
In tal caso occhio che non usi il destroy della tua classe, ma quello di object.In quel caso ti ritrovi nei guai per il motivo che indicava xinyiman (http://www.lazaruspascal.it/index.php?action=profile;u=1).
La "out of memory" potrebbe essere generata anche per altri motivi. La free and nil dovrebbe darti un SIGSEG in caso di rogne.
Hai provato a mettere degli Writeln per"loggare" i passaggi?Numero del thread,dimensione file, bla bla.Le informazioni che ti possono servire per capire in che momento scatta lo sfondamento (apparente) di memoria?
http://wiki.freepascal.org/paszlib#Unzip_file_to_a_stream (http://wiki.freepascal.org/paszlib#Unzip_file_to_a_stream)
Il fatto che qui faccia la copia del testo dentro la memo è un caso simile al tuo?Altrimenti al posto della loadFromStream, non puoi usare direttamente lo stream?La distruzione viene delegata all'utilizzatore. Ergo puoi farne quello che vuoi.
Procedure TUnZipper.CloseOutput(Item : TFullZipFileEntry; var OutStream: TStream);
Begin
if Assigned(FOnDoneStream) then
begin
FOnDoneStream(Self, OutStream, Item);
OutStream := nil;
end
else
FreeAndNil(OutStream);
DoEndOfFile;
end;
Perchè in altrernativa, potresti costruirti tu lo stream da usare come destinazione dell'unzip. Frutti la callback OnCreateStream.In questo modo non hai duplicazione, spari direttamente il dato decompesso dove vuoi tu.Dai che quando ha finito ti chiama la Done. ;)Insomma, rivisitando la logica del giro, poresti toglierti il dubbio della duplicazione.
:)
Stilgar