There are two exceptions raised while calling conn.Disconnect.
First exception TZOracleConnection.InternalClose:953 -> TZOracleTransaction.BeforeDestruction:1507 -> TZOracleTransaction.Rollback:1631 -> TZOracleConnection.HandleErrorOrWarning:1416
Project Project3.exe raised exception class EZSQLConnectionLost with message 'SQL Error: ORA-03113: end-of-file on communication channel
Process ID: 4256
Session ID: 406 Serial number: 45913
Code: 3113 SQL: TRANSACTION ROLLBACK'.
Second exception TZOracleConnection.InternalClose:961 -> TZOracleConnection.HandleErrorOrWarning:1416
Project Project3.exe raised exception class EZSQLException with message 'SQL Error: OCI_INVALID_HANDLE
Code: -2 Message: DISCONNECT FROM "DEVELOPER"'.
But still, I think you are checking the
wrong end of the code. If I modify TZOracleConnection.BeforeDestruction:
Code: Select all
procedure TZOracleTransaction.BeforeDestruction;
var Status: sword;
begin
inherited BeforeDestruction;
if FOCITrans <> nil then begin
try
fSavepoints.Clear;
try
if FStarted then
RollBack; // <- Exception can be raised here, normally NOTHING below this line gets executed
Status := FOwner.FPlainDriver.OCIHandleFree(FOCITrans, OCI_HTYPE_TRANS);
if Status <> OCI_SUCCESS then
FOwner.HandleErrorOrWarning(FOwner.FErrorHandle, Status, lcTransaction, 'OCIHandleFree', Self); // <- Exception can be raised here, so after swallowing the first exception NOTHING below this line gets executed
except
// Swallow exception, so destructor can finish in peace
end;
finally
FOCITrans := nil;
end;
end;
fSavepoints.Free; // <- With the original design, the code will NEVER reach this line, thus leaking this object too with TZOracleTransaction
end;
This way no exception is raised when Delphi is trying to dispose the transaction object, there are no leaks at all; not even the fSavePoints TStringList. The leak is not due to server resources, it's due to the destructor design of the TZTransaction object.
Edit: It seems that the transaction is trying to rollback and free the handle of a non existing connection, therefore raising exceptions. These must only be called if we are sure that the connection is still alive.
To try to demonstrate what is happening, consider the below code:
Code: Select all
TMyClass = Class
strict private
_sl: TStringList;
public
Constructor Create; ReIntroduce;
Destructor Destroy; Override;
End;
constructor TMyClass.Create;
begin
inherited;
_sl := TStringList.Create;
end;
destructor TMyClass.Destroy;
begin
Raise Exception.Create('Leak');
_sl.Free;
inherited;
end;
TMyClass.Create.Free;
According to FastMM, this will leak:
---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:
1 - 12 bytes: TMyClass x 1
13 - 20 bytes: Unknown x 1
69 - 76 bytes: TStringList x 1
This is the exact thing happening to TZOracleTransaction. But instead of MyClass, it's the transaction object, the stringlist is fSavePoints.
P.s.: It seems ReportMemoryLeaksOnShutdown does not work on console applications on 10.4.1, this is why I had to rely on DeLeaker.