AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Abort verursacht MemoryLeak ?

Ein Thema von Int3g3r · begonnen am 22. Sep 2020 · letzter Beitrag vom 25. Sep 2020
Antwort Antwort
Int3g3r

Registriert seit: 28. Nov 2018
Ort: Schweiz
118 Beiträge
 
Delphi 10.3 Rio
 
#1

Abort verursacht MemoryLeak ?

  Alt 22. Sep 2020, 18:12
Guten Tag,

Ich habe hier ein MemoryLeakOnShutdown das verursacht wird wenn ich ein Abort; and der kommentierten Stelle mache. Wenn ich das Abort auskommentiere verschwindet das MemoryLeak.
Naja der Code Block ist sowieso abgearbeitet also könnte ich das Abort weglassen.
Wenn aber durch eine Änderung noch mehr Code hinzukommt, komme ich um das Abort nicht herum da es sich um einen Fehler handelt, und die Routine abgebrochen werden soll.

Zitat:
13-20 bytes: Unknown x1
37-44 bytes: Unknown x1
69-76 bytes: TStringList x1
85-92 bytes: UnicodeString x2
93-100 bytes: UnicodeString x2
Warum entsteht hier ein MemoryLeak ?

Delphi-Quellcode:
procedure TMail.sendMassMail(_from, _subject: String; _delayInSeconds:Int64);
var i: Integer;
    msg: TIdMessage;
begin
  try
      if not isFileEmpty(AppPath+mailListFilePath) then
      begin
        mailListText := TStringList.Create;
        mailListText.LoadFromFile(AppPath+mailListFilePath);
    
        for i := mailListText.Count-1 downto 0 do
        begin
          if Trim(mailListText[i]) = 'then
          begin
            mailListText.Delete(i);
          end
          else
          begin
            mailListText[i] := Trim(mailListText[i]);
          end;
        end;
      end
      else
      begin
        ShowMessage('MailListe ist leer. Abbruch!');
        abort;
      end;

      if mailListText.Count < 1 then
      begin
        ShowMessage('Keine Empfänger in der MailListe. Abbruch!');
        abort;
      end;

      if mailInit(_from,_subject) then
      begin
        if (mailListText.Count > 0) and (mailListText.Count < autoMailMaxCount) then
        begin
          msg := prepareMailMsg(_from,_subject);
            for i := 0 to mailListText.Count-1 do
            begin
              if (i mod autoMailPackageSendSize = 0) and (i <> 0) then
              begin
                 Sleep(_delayInSeconds*1000);
                 sendMail(mailListText[i],msg);
              end
              else
              begin
                 sendMail(mailListText[i],msg);
              end;
            end;
        end
        else
        begin
          Showmessage('EMails können nicht an mehr als ' + IntToStr(autoMailMaxCount)+
                      ' Empfänger gesendet werden.'+#13#10+'Zu viele Empfänger in der Liste. Abbruch!' );
          abort; // Dieses Abort verursacht das MemoryLeak, die anderen sind noch nicht getestet!
        end;
      end;
  
  finally
    FreeAndNil(msg);
    FreeAndNil(mailListText);
    FreeAndNil(attachmentsText);
    FreeAndNil(bodyText);
  end;
end;
Ich habe im Debugger getestet ob das TryFinally sauber durchläuft und das tut es, auch wenn das Abort nicht auskommentiert ist. Also nach dem Abort läuft er ins finally.

Daher verstehe ich nicht warum ich durch dieses Abort ein MemoryLeak erhalte.

Mfg Int3g3r
  Mit Zitat antworten Zitat
Klaus01
Online

Registriert seit: 30. Nov 2005
Ort: München
5.571 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Abort verursacht MemoryLeak ?

  Alt 22. Sep 2020, 18:35
.. wenn Du exit anstelle von abort verwenden würdest:

Zitat:
Raises a silent exception.

Use Abort to escape from an execution path without reporting an error.

Abort raises a special "silent exception" (EAbort), which operates like any other exception, but does not display an error message to the end user. Abort redirects execution to the end of the last exception block.
Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.272 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Abort verursacht MemoryLeak ?

  Alt 22. Sep 2020, 18:55
Jupp, in dieser Funktion wird das Finally immer ausgeführt.
Die Speicherlecks sind also eher außerhalb dieser Methode zu suchen.

Und ja, Exit verlässt nur diese Methode,
aber Abort bricht auch alle aufrufenden Methoden ab.
Wenn es dann ein Speicherleck gibt, nach Abort oder einer anderen exception, dann hast du vermutlich irgendwo den Ressourcenschutzblock vergessen.

Fehlerbehandlung mit ShowMessage, dafür sollte man auch gesteinigt werden.
Versuche mal dieses sendMassMail innerhalb eines Try-Except zu benutzen. Ein Raise anstatt der Message würde die Behandlung erleichtern, denn so kann man außerhalb den Fehler nicht behandeln, loggen oder sonstwas.

Außerdem wäre es nett, wenn du bitte erstmal die Compiler-Warnungen beachten würdest.
Ich bin mir fast sicher, dass es für die Variable "msg" mindestens eine Warnung gibt.
Zitat:
Delphi-Quellcode:
try
  msg := ...
finally
  FreeAndNil(msg);
end;
Den "msg" ist nicht initialisiert.
Mögliche Lösungen:
Delphi-Quellcode:
msg := ...
try
  
finally
  FreeAndNil(msg);
end;
oder
Delphi-Quellcode:
msg := nil;
try
  msg := ...
finally
  FreeAndNil(msg);
end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (22. Sep 2020 um 18:59 Uhr)
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
7.929 Beiträge
 
Delphi XE4 Professional
 
#4

AW: Abort verursacht MemoryLeak ?

  Alt 22. Sep 2020, 19:36
Hallo,
wo ist denn z.B. mailListText definiert?
Warum ist das keine lokale Variable?

Dann würde ich das so machen

TMailListText = class(TStringList);

und dann
mailListText := TMailListText.Create;

Dann siehst Du ja dann, ob es diese StringList ist, die "leaked".
Heiko

Geändert von hoika (22. Sep 2020 um 19:49 Uhr)
  Mit Zitat antworten Zitat
Int3g3r

Registriert seit: 28. Nov 2018
Ort: Schweiz
118 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Abort verursacht MemoryLeak ?

  Alt 25. Sep 2020, 08:49
Zitat:
.. wenn Du exit anstelle von abort verwenden würdest:
Exit verlässt nur die aktuelle Methode. Beim Beispiel unten würden "erstelleMail" und "sendMail" ausgeführt.
Darum verwende ich abort und nicht exit. Klar könnte ich jede Methode als Funktion schreiben und danach ein true/false zurückgeben. Dann kann ich aber nicht auf mehere Feher in der funktion reagieren.

Delphi-Quellcode:
// Dies ist imaginärer Code nur zum verdeutlichen warum ich Abort verwende:
procedure TForm1.Button1Click(Sender: TObject);
begin
  setParameter;
  erstelleMail;
  sendMail;
end;

procedure TForm1.erstelleMail;
begin
  //Mail Erstellen
end;

procedure TForm1.sendMail;
begin
  //Mail Senden
end;

procedure TForm1.setParameter;
begin
  //Parameter Setzen
  exit;
end;

Zitat:
Fehlerbehandlung mit ShowMessage, dafür sollte man auch gesteinigt werden.
Gehe ich davon aus. Leider Programmiert mein Ausbildner genau so.
Wie mache ich es besser ? Ein Bespiel / Tutorial wäre hilfreich.


Zitat:
wo ist denn z.B. mailListText definiert?
Warum ist das keine lokale Variable?
mailListText ist ein Klassenmember. Benötige ich nur 1x und ich muss von mehreren prozeduren/funktionen innerhalb der Klasse darauf zugreifen können.


Einmal über das Problem schlafen und man findet das Problem in 10 Minuten ....

Delphi-Quellcode:
procedure TfrmMain.Button1Click(Sender: TObject);
var list: TStringList;
begin
  list := TStringList.Create;
  list.Add('C:\...\bin\Win32\attach\Leaks.PNG');
  list.Add('C:\...\bin\Win32\attach\recompile.PNG');
  list.Add('C:\...\bin\Win32\attach\TelSpick.exe');
  list.Add('C:\...\bin\Win32\attach\Unbenannt.PNG');

  Mail := TMail.Create;
  Mail.sendMassMail('mail@gmx.ch','MassMail',10); //<- Abort

  list.Free; //<- Wird bei Abort nicht mehr Freigegeben ....
end;
Danke für die Hilfe !

Gruss Int3g3r
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
7.929 Beiträge
 
Delphi XE4 Professional
 
#6

AW: Abort verursacht MemoryLeak ?

  Alt 25. Sep 2020, 09:41
Hallo,
Delphi-Quellcode:
list := TStringList.Create;
try
  list.Add('C:\...\bin\Win32\attach\Leaks.PNG');
  list.Add('C:\...\bin\Win32\attach\recompile.PNG');
  list.Add('C:\...\bin\Win32\attach\TelSpick.exe');
  list.Add('C:\...\bin\Win32\attach\Unbenannt.PNG');

  Mail := TMail.Create;
  Mail.sendMassMail('mail@gmx.ch','MassMail',10); //<- Abort
finally
  list.Free;
end;
Wenn es nicht anders geht:
Außerdem arbeitest Du wieder mit quasi-globalen Variablen, hier Mail.
Ich würde Mail z.B. im FormCreate erzeugen und in FormDestroy freigeben.
Heiko
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
1.721 Beiträge
 
Delphi 7 Professional
 
#7

AW: Abort verursacht MemoryLeak ?

  Alt 25. Sep 2020, 10:37
Hier steht was zu Abort

Damit wird klar, warum das list.free nicht aufgerufen wird.
Delphi-Quellcode:
  try
    Funktion_die_im_Fehlerfalle_Abort_aufruft;
  except
    on e : EAbort do begin
      ShowMessage('Abort wurde aufgerufen.');
    end;
    on e : Exception do begin
      MessageDLG(e.Message,mtError,[mbok],0);
    end;
  end;
Abort ist letztlich auch nur 'ne Exception, deren Meldung "verschluckt" wird. Man kann sie aber im Exceptionhandling "abfangen" und damit auch in dem Fall ein "vernünftiges" Weiterlaufen des Programmes sicherstellen.

Mal ein annähernd sinnfreies Beispiel zum rumprobieren:
Delphi-Quellcode:
function Funktion_Bricht_Im_Fehlerfalle_Mit_Abort_ab(i : Integer) : Integer;
begin
  Result := 4812;
  if i < 0 then begin // Als Fehlerfall ist hier einfach mal i < 0 definiert.
    Abort;
  end else begin
    Result := Result div i;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  list : TStringList;
  k : Integer;
  i : Integer;
begin
  list := TStringList.Create;
  list.Add('irgendwas');
  list.Add('nochwas');
  i := 47;
  k := 12;
  try
    try
      // Wahlweise mit i = 0, i = -1 und i = 1 ausprobieren
      // und die Reihenfolge der Wertzuweisung zu i mal ändern.
      i := 1;
      k := Funktion_Bricht_Im_Fehlerfalle_Mit_Abort_ab(i);
      i := -1;
      k := Funktion_Bricht_Im_Fehlerfalle_Mit_Abort_ab(i);
      i := 0;
      k := Funktion_Bricht_Im_Fehlerfalle_Mit_Abort_ab(i);
    except
      on e : EAbort do begin
        MessageDlg(e.Message,mtError,[mbOk],0);
      end;
      on e : Exception do begin
        MessageDlg(e.Message,mtError,[mbOk],0);
      end;
    end;
    ShowMessage(Format('i = %d, k = %d',[i,k]));
  finally
    list.Free;
  end;
end;
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +2. Es ist jetzt 10:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf