Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: AndreaM - Luglio 30, 2013, 08:10:42 pm

Titolo: Perdita di memoria con TStringList?
Inserito da: AndreaM - Luglio 30, 2013, 08:10:42 pm
Salve a tutti!
Mi spiego! Ho un semplice programma in cui sto testando l'uso di TStringList in una Function, e ho attivato la funzione del compilatore per testare le perdite di memoria con heaptrc.
Se io creo una funzione del tipo:
Codice: [Seleziona]
function TForm1.Prova: TStringList;
begin
result:=TStringList.Create;
with result do
    begin
    Add('Prova1');
    add('Prova2');
    Add('Prova3');
    end;
end;       

Poi con un pulsante verifico la funzione in un memo:
Codice: [Seleziona]
procedure TForm1.Button4Click(Sender: TObject);
begin
m1.Lines.AddStrings(Prova);
Prova.Free; 
end; 

1) Prova.Free è necessario? oppure la memoria viene liberata dal proprietario, cioè Form1
2) Sia con che senza Prova.Free i risultati sono quelli attesi, la applicazione si chiude senza errori, ma heaptrc mi segnala che ci sono 2 blocchi di memoria non liberati!!
N.B. Ovviamente non premendo il pulsante la applicazione si chiude senza perdite di memoria!

Chi mi spiega dove sbaglio?
grazie
Andrea

Titolo: Re:Perdita di memoria con TStringList?
Inserito da: El Salvador - Luglio 30, 2013, 08:39:04 pm
Citazione
1) Prova.Free è necessario? oppure la memoria viene liberata dal proprietario, cioè Form1
No, perchè è un oggetto che crei te ed è slegato da Form1. Inoltre se il tuo intento è quello di liberare la memoria di Prova è sbagliato. Infatti seguendo il tuo codice, tu crei due TStringList.
Codice: [Seleziona]
m1.Lines.AddStrings(Prova);
La funzione Prova restituisce il primo TStringList creato e lo da come parametro al AddStrings, cosi aggiunge le stringhe al memo.
Codice: [Seleziona]
Prova.Free;  
Invece questo codice crei il secondo TStringList, ma lo liberi subito. Praticamente fai eseguire al programma un lavoro completamente inutile (e sbagliato).

Perchè? Perchè nella funzione Prova gli hai detto di creare un TStringList e di restituirtelo come risultato. Quindi ogni volta che richiamerai Prova, creerai un TStringList.

Per rimediare, dovrai creare il primo TStringList, inserirlo in una variabile (cosi poterlo usare tranquillamente per fare quello che devi fare), aggiungerlo al memo e poi liberarlo (quando non ti servirà più). Come?
Citazione
procedure TForm1.Button1Click(Sender: TObject);
var
  sList: TStringList;
begin
  sList := Prova;
  m1.Lines.AddStrings(sList);
  sList.Free;
end; 
Titolo: Re:Perdita di memoria con TStringList?
Inserito da: nomorelogic - Luglio 31, 2013, 09:38:25 am
@AndreaM
un suggerimento

quando scrivi una procedure o una function che alloca risorse, dai un nome significativo (il tempo passa e non sempre ci si ricorda di come abbiamo scritto un programma nel passato), ad esempio, nel tuo caso:
function Tform1.CreateAndPopulateProva: TStringList;

in questo modo l'evento OnClick del bottone sarebbe stato:
Codice: [Seleziona]
procedure TForm1.Button4Click(Sender: TObject);
begin
   m1.Lines.AddStrings(CreateAndPopulateProva);
   CreateAndPopulateProva.Free; 
end; 

non cambia nulla ovviamente ma forse l'errore sarebbe stato più evidente ;)
Titolo: Re:Perdita di memoria con TStringList?
Inserito da: AndreaM - Luglio 31, 2013, 05:34:28 pm
Risolto!
Grazie a tutti e due!
Andrea