AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language AcquireExceptionObject() / ReleaseExceptionObject()
Thema durchsuchen
Ansicht
Themen-Optionen

AcquireExceptionObject() / ReleaseExceptionObject()

Ein Thema von Der schöne Günther · begonnen am 31. Mai 2017 · letzter Beitrag vom 6. Jun 2017
Antwort Antwort
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.384 Beiträge
 
Delphi 12 Athens
 
#1

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 31. Mai 2017, 15:13
Hier werden ständig so viele Exceptions ausgelöst,
wenn die nicht freigegeben würden (im END), dann würde bei uns doch auch ständig der Speicher ausgehn.

Aktuell noch Delphi XE, aber hier sieht der Code gleich aus.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 31. Mai 2017, 15:36
Habe mal mit Berlin einen kleinen Test geschrieben:

Delphi-Quellcode:
procedure ttestexception.Test1;
var p : Pointer;
begin
  try
   Writeln('Test 1');

   raise etestexception.Create;
  except
   Writeln('Exceptblock 1');
   Writeln('AcquireExceptionObject');
   p := AcquireExceptionObject;
   ReleaseExceptionObject;
  end;
 Writeln('Leave Test1');

end;

procedure ttestexception.Test2;
var p : Pointer;
begin
  try
   writeln;
    Writeln('Test 2');

   raise etestexception.Create;
  except
   Writeln('Exceptblock 2');
  end;
 Writeln('Leave Test2');

end;

{ EtestException }

constructor EtestException.create;
begin
  inherited create('Test');
  writeln('Create EtestException ');
end;

destructor EtestException.Destroy;
begin
  writeln('Free EtestException ');
  inherited;
end;
Result:
Code:
Test 1
Create EtestException
Exceptblock 1
AcquireExceptionObject
Leave Test1

Test 2
Create EtestException
Exceptblock 2
Free EtestException
Leave Test2
Done
Wird also nicht freigegeben
Fritz Westermann
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.199 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 31. Mai 2017, 15:44
Danke für den Test.

Mein Test wäre jetzt gewesen es in einer Schleife aufzurufen und in den Task-Manager zu schauen wie sich der Speicher füllt. Das ist natürlich schlauer
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.384 Beiträge
 
Delphi 12 Athens
 
#4

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 31. Mai 2017, 16:12
Hatte ich doch gesagt
* ReleaseExceptionObject macht halt nichts, wie schon richtig gesehn, aber sooooo sehr stört es jetzt nicht
* aber AcquireExceptionObject funktioniert dennoch (wäre blöd, wenn nicht)

Hatte das auch grade mal schnell als Test gebastelt:
Delphi-Quellcode:
type
  EMyTest = class(Exception)
  public
    // TObject
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    class function NewInstance: TObject; override;
    procedure FreeInstance; override;
    //destructor Destroy; override;
  protected
    // Exception
    procedure RaisingException(P: PExceptionRecord); override;
  public
    // Exception
    constructor Create(const Msg: string);
    destructor Destroy; override;
  end;

procedure EMyTest.AfterConstruction;
begin
  //Form5.Memo1.Lines.Add('Exception.AfterConstruction');
  inherited;
end;

procedure EMyTest.BeforeDestruction;
begin
  //Form5.Memo1.Lines.Add('Exception.BeforeDestruction');
  inherited;
end;

constructor EMyTest.Create(const Msg: string);
begin
  Form5.Memo1.Lines.Add('Exception.Create ' + Msg);
  inherited;
end;

destructor EMyTest.Destroy;
begin
  Form5.Memo1.Lines.Add('Exception.Destroy ' + Message);
  inherited;
end;

procedure EMyTest.FreeInstance;
begin
  //Form5.Memo1.Lines.Add('Exception.FreeInstance');
  inherited;
end;

class function EMyTest.NewInstance: TObject;
begin
  //Form5.Memo1.Lines.Add('Exception.NewInstance');
  Result := inherited;
end;

procedure EMyTest.RaisingException(P: PExceptionRecord);
begin
  Form5.Memo1.Lines.Add('Exception.RaisingException');
  inherited;
end;

procedure TForm5.FormCreate(Sender: TObject);
var
  E: {Exception}TObject;
begin
  {$REGION 'normal'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** normal');
  try
    Memo1.Lines.Add('raise Exception.Create()');
    //raise Exception.Create('Fehlermeldung');
    raise EMyTest.Create('Fehlermeldung');
    Memo1.Lines.Add('');
  except
    Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('end');
  end;
  Memo1.Lines.Add('finish');
  {$ENDREGION}

  {$REGION 'release'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** release');
  try
    Memo1.Lines.Add('raise Exception.Create()');
    //raise Exception.Create('Fehlermeldung');
    raise EMyTest.Create('Fehlermeldung');
    Memo1.Lines.Add('');
  except
    Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('ReleaseExceptionObject');
    ReleaseExceptionObject;
    Memo1.Lines.Add('end');
  end;
  Memo1.Lines.Add('finish');
  {$ENDREGION}

  {$REGION 'acquire'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** acquire');
  try
    Memo1.Lines.Add('raise Exception.Create()');
    //raise Exception.Create('Fehlermeldung');
    raise EMyTest.Create('Fehlermeldung');
    Memo1.Lines.Add('');
  except
    Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('AcquireExceptionObject');
    E := AcquireExceptionObject;
    Memo1.Lines.Add('end');
  end;
  Memo1.Lines.Add('E.Free');
  E.Free;
  Memo1.Lines.Add('finish');
  {$ENDREGION}

  {$REGION 're-raise'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** re-raise');
  try
    try
      Memo1.Lines.Add('raise Exception.Create()');
      //raise Exception.Create('Fehlermeldung');
      raise EMyTest.Create('Fehlermeldung');
      Memo1.Lines.Add('');
    except
      Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
      Memo1.Lines.Add('raise E');
      raise;
      Memo1.Lines.Add('end');
    end;
    Memo1.Lines.Add('finish');
  except
    Memo1.Lines.Add('except(2) ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('end(2)');
  end;
  Memo1.Lines.Add('finish(2)');
  {$ENDREGION}

  {$REGION 'new-raise'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** new-raise');
  try
    try
      Memo1.Lines.Add('raise Exception.Create(1)');
      //raise Exception.Create('Fehlermeldung_1');
      raise EMyTest.Create('Fehlermeldung_1');
      Memo1.Lines.Add('');
    except
      Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
      Memo1.Lines.Add('raise Exception.Create(2)');
      raise EMyTest.Create('Fehlermeldung_2');
      Memo1.Lines.Add('end');
    end;
    Memo1.Lines.Add('finish');
  except
    Memo1.Lines.Add('except(2) ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('end(2)');
  end;
  Memo1.Lines.Add('finish(2)');
  {$ENDREGION}


  {$REGION 'acquire + re-raise'}
  Memo1.Lines.Add('');
  Memo1.Lines.Add('***** acquire + re-raise');
  try
    Memo1.Lines.Add('raise Exception.Create()');
    //raise Exception.Create('Fehlermeldung');
    raise EMyTest.Create('Fehlermeldung');
    Memo1.Lines.Add('');
  except
    Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('AcquireExceptionObject');
    E := AcquireExceptionObject;
    Memo1.Lines.Add('end');
  end;
  try
    raise E;
  except
    Memo1.Lines.Add('except ' + Exception(ExceptObject).Message);
    Memo1.Lines.Add('end');
  end;
  Memo1.Lines.Add('finish');
  {$ENDREGION}
end;
Code:
***** normal
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
end
Exception.Destroy Fehlermeldung
finish

***** release
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
ReleaseExceptionObject
end
Exception.Destroy Fehlermeldung
finish

***** acquire
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
AcquireExceptionObject
end
E.Free
Exception.Destroy Fehlermeldung
finish

***** re-raise
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
raise E
except(2) Fehlermeldung
end(2)
Exception.Destroy Fehlermeldung
finish(2)

***** new-raise
raise Exception.Create(1)
Exception.Create Fehlermeldung_1
Exception.RaisingException
except Fehlermeldung_1
raise Exception.Create(2)
Exception.Create Fehlermeldung_2
Exception.RaisingException
Exception.Destroy Fehlermeldung_1
except(2) Fehlermeldung_2
end(2)
Exception.Destroy Fehlermeldung_2
finish(2)

***** acquire + re-raise
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
AcquireExceptionObject
end
Exception.RaisingException
except Fehlermeldung
end
Exception.Destroy Fehlermeldung
finish
Tja, das kaputte ReleaseExceptionObject müsste ja eigentlich so aussehn, wenn es funktionieren würde:
Code:
***** release
raise Exception.Create()
Exception.Create Fehlermeldung
Exception.RaisingException
except Fehlermeldung
ReleaseExceptionObject
Exception.Destroy Fehlermeldung <<<<<<<<<<<<<<<<<
end
finish
anstatt
Code:
...
ReleaseExceptionObject
end
Exception.Destroy Fehlermeldung <<<<<<<<<<<<<<<<<
finish
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (31. Mai 2017 um 16:23 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.199 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 1. Jun 2017, 12:10
Vielleicht möchten alle die können voten:

https://quality.embarcadero.com/browse/RSP-18259
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.384 Beiträge
 
Delphi 12 Athens
 
#6

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 1. Jun 2017, 13:08
Zitat:
Delphi-Quellcode:
try
  raise EProgrammerNotFound.Create('nope');
except
  AcquireExceptionObject();
  ReleaseExceptionObject(); // << this is an empty procedure
end;
Das ReleaseExceptionObject würde in diesem Code sowieso nie was machen, selbst wenn es was machen würde.

AcquireExceptionObject hängt die Exception von dem Exception-Block ab und gibt sie dir
und ReleaseExceptionObject würde die Exception des Exception-Block freigeben, welche es da aber schon nicht mehr gibt.

rein logisch sind diese beiden Codes identisch
except ReleaseExceptionObject; end; = except AcquireExceptionObject.Free; end;
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.199 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 1. Jun 2017, 13:31
Das ist ja nur ein Test. Der Klassische Fall das Exception-Objekt außerhalb des try..except-Blocks weiterleben lassen zu wollen ist es bspw. in einem anderen Thread zu verarbeiten (Exception-Logging, ...).

So macht das TThread auch damit man nach Thread-Ende noch das Feld FatalException auslesen kann.

Und ja, ich weiß dass ich das zurückgegebene TObject / Exception "normal" freigeben kann. Es geht aber darum dass die Doku ein Laufzeitverhalten verspricht das überhaupt nicht existiert. Dass Code existiert der anscheinend überhaupt nicht aktiv ist da er von einer leeren Prozedur verdeckt wird.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.384 Beiträge
 
Delphi 12 Athens
 
#8

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 1. Jun 2017, 13:49
Es lassen sich nicht alle Dinge auf allen Platformen gleich umsetzen und das ist eine plaformübergreifende Funktion.

Wenn es in einer Platform kein äquivalentes Verhalten gibt und sich das Standardverhalten nicht extrem wiedersprüchlich verhalten würde, dann macht man dort einfach nichts und schon ist gut.



Da finde ich es "schwachsinniger", dass .Free unter ARC garnichts macht, obwohl man dort etwas genau jetzt freigeben will.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.045 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#9

AW: AcquireExceptionObject() / ReleaseExceptionObject()

  Alt 6. Jun 2017, 11:52
Die Doku is kompletter Unfug. ReleaseExceptionObject kann gar nicht das machen, was da steht, weil man AcquireExceptionObject so oft und auf so viele Exceptions machen kann, wie man will. Wenn man sie freigeben möchte, reicht ein einfaches Free bzw auf nil setzen der Variable unter ARC (ab Delphi 10.2).

Vorher war die Funktion unter ARC noch verbuggt, da sie einen Pointer zurücklieferte und somit ARC umging (siehe https://quality.embarcadero.com/browse/RSP-13652)

Korrektur: Das mit dem RefCount in ReleaseExceptionObject ist nur unter dem IFDEF PC_MAPPED_EXCEPTIONS und hat mit ARC nix zu tun - guckstu: http://docwiki.embarcadero.com/RADSt...ped_Exceptions
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 6. Jun 2017 um 11:58 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


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 +1. Es ist jetzt 13:25 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz