* * * *

Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

Trascinare un file nel programma
DB concetti fondamentali e ZeosLib
Recuperare codice HTML da pagina web
Mandare mail con Lazarus
Stabilire il sistema operativo
Esempio lista in pascal
File INI
Codice di attivazione
Realizzare programmi multilingua
Lavorare con le directory
Utilizzare Unità esterne
TTreeView
TTreeview e Menu
Generare controlli RUN-TIME
LazReport, PDF ed immagini
Intercettare tasti premuti
Ampliare Lazarus
Lazarus e la crittografia
System Tray con Lazarus
UIB: Unified Interbase
Il file: questo sconosciuto
Conferma di chiusura di un applicazione
Liste e puntatori
Overload di funzioni
Funzioni a parametri variabili
Proprietà
Conversione numerica
TImage su Form e Panel
Indy gestiore server FTP lato Client
PopUpMenu sotto Pulsante (TSpeedButton)
Direttiva $macro
Toolbar
Evidenziare voci TreeView
Visualizzare un file Html esterno
StatusBar - aggirare l'errore variabile duplicata
Da DataSource a Excel
Le permutazioni
Brute force
Indy 10 - Invio email con allegati
La gestione degli errori in Lazarus
Pascal Script
Linux + Zeos + Firebird
Dataset virtuale
Overload di operatori
Lavorare con file in formato JSON con Lazarus
Zeos ... dietro le quinte (prima parte)
Disporre le finestre in un blocco unico (come Delphi)
Aspetto retrò (Cmd Line)
Lazarus 1.0
Come interfacciare periferica twain
Ubuntu - aggiornare free pascal e lazarus
fpcup: installazioni parallele di lazarus e fpc
Free Pascal e Lazarus sul Raspberry Pi
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Creare un server multithread
guida all'installazione di fpc trunk da subversion in linux gentoo
Indice
DB concetti fondamentali e connessioni standard
Advanced Record Syntax
DB concetti fondamentali e DBGrid
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
Advanced Record Syntax: un esempio pratico
Superclasse form base per programmi gestionali (e non)
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Installare lazarus su mac osx sierra
immagine docker per lavorare con lazarus e free pascal
TDD o Test-Driven Development
Benvenuto! Effettua l'accesso oppure registrati.
Aprile 19, 2024, 07:45:29 pm

Inserisci il nome utente, la password e la durata della sessione.

384 Visitatori, 0 Utenti

Autore Topic: Problemi di memoria ... RAM  (Letto 2776 volte)

bonmario

  • Hero Member
  • *****
  • Post: 1300
  • Karma: +10/-1
Problemi di memoria ... RAM
« il: Novembre 27, 2018, 08:24:04 pm »
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:
Codice: [Seleziona]
  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
« Ultima modifica: Novembre 28, 2018, 01:32:47 pm da bonmario »

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3249
  • Karma: +12/-0
Re:Problemi di memoria ... RAM
« Risposta #1 il: Novembre 28, 2018, 01:24:40 pm »
Ciao bonmario, non penso che il problema sia la memoria sovraccaricata dai file letti, perchè quella se la gestisce il sistema operativo ricorrendo anche all'harddisk quando serve.

La prima cosa che mi sento di suggerirti è di sostituire il

    FreeAndNil(aStream);

con

aStream.Free;
aStream:=nil;

Questo perchè se dentro il destructor della classe hai del codice da eseguire il FreeAndNil non lo esegue. Se questo non aiuta sposta il FreeAndNil fuori dalla funzione. 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.
Ieri è passato, domani è futuro, oggi è un dono...

bonmario

  • Hero Member
  • *****
  • Post: 1300
  • Karma: +10/-1
Re:Problemi di memoria ... RAM
« Risposta #2 il: Novembre 28, 2018, 01:30:28 pm »
La prima cosa che mi sento di suggerirti è di sostituire il

    FreeAndNil(aStream);

Ho sempre usato FreeAndNil, perché il suo sorgente è questo:

Codice: [Seleziona]
    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:
Citazione
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
« Ultima modifica: Novembre 28, 2018, 01:32:25 pm da bonmario »

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3249
  • Karma: +12/-0
Re:Problemi di memoria ... RAM
« Risposta #3 il: Novembre 28, 2018, 01:42:27 pm »
Funzionare funziona, però se hai una classe dove nel destructor gestisci la liberazione di altra memoria allora può creare problemi. Ipotizza che la tua classe faccia riferimento ad altra memoria attraverso i puntatori usando il FreeAndNil liberi la porzione di memoria occupata dalla tua classe ma non viene eseguito il codice del destructor e quindi la memoria occupata a cui facevi riferimento con i puntatori rimane occupata.

Per quanto riguarda la tua domanda non penso si possa ottimizzare più di così.
Ieri è passato, domani è futuro, oggi è un dono...

bonmario

  • Hero Member
  • *****
  • Post: 1300
  • Karma: +10/-1
Re:Problemi di memoria ... RAM
« Risposta #4 il: Novembre 28, 2018, 06:20:38 pm »
Mi stai dando una bruttissima notizia ... penso di avere centinaia di FreeAndNil sparse nei miei sorgenti !!!

Ciao, Mario

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3249
  • Karma: +12/-0
Re:Problemi di memoria ... RAM
« Risposta #5 il: Novembre 29, 2018, 08:10:22 am »
Mi dispiace, ma l'ho imparato sulla mia pelle.
Ieri è passato, domani è futuro, oggi è un dono...

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2382
  • Karma: +10/-0
Re:Problemi di memoria ... RAM
« Risposta #6 il: Novembre 29, 2018, 03:32:36 pm »
Bonmario,hai rimosso il "override" dai tuoi distruttori?
Codice: [Seleziona]
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.
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
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.
Codice: [Seleziona]
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
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1300
  • Karma: +10/-1
Re:Problemi di memoria ... RAM
« Risposta #7 il: Novembre 29, 2018, 04:29:48 pm »
Alla fine ho risolto.
I problemi erano 2:
- uno mio che non liberavo la memoria di un oggetto (trovato tramite "heaptrc")
- l'altro era dovuto al fatto che, per facilitarmi le operazioni di lettura, leggevo lo stream (che è un XML), con "TXMLDocument" della unit Laz2Dom.

TXMLDocument, a fronte di un XML che su disco occupa 50 mega, mi occupa circa 400 mega, per un totale di circa 450 mega.
Quando più thread in contemporanea gestivano 3 o 4 di questi files, avevo il problema.

Ora ho risolto leggendo lo stream XML con SAX invece che con DOM.

Grazie a tutti, Mario

 

Recenti

How To

Utenti
  • Utenti in totale: 785
  • Latest: gmax
Stats
  • Post in totale: 18772
  • Topic in totale: 2233
  • Online Today: 578
  • Online Ever: 900
  • (Gennaio 21, 2020, 08:17:49 pm)
Utenti Online
Users: 0
Guests: 384
Total: 384

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.