Jump to content
iqrf

TPyDelphiWrapper - memory leaks

Recommended Posts

Hi,

i have this code

TColumn = class(TPersistent)
private
  FHeaderName: String;
  FVisible: Boolean;
  FWidth: Integer;
  FPosition: Integer;
  procedure SetHeaderName(const Value: String);
  procedure SetVisible(const Value: Boolean);
  procedure SetWidth(const Value: Integer);
  procedure SetPosition(const Value: Integer);
public
  property HeaderName: String read FHeaderName write SetHeaderName;
  property Visible: Boolean read FVisible write SetVisible;
  property Width: Integer read FWidth write SetWidth;
  property Position: Integer read FPosition write SetPosition;
end;

TColumnWrapper = class(TPyClassWrapper<TColumn>)
  constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); override;
end;

TTerminalLogSettings = class(TPersistent)
private
  fColumn: TDictionary<String,TColumn>;
  function GetAutoScroll: Boolean;
  function GetSeparatorH: Boolean;
  function GetSeparatorV: Boolean;
  function GetViewData: Boolean;
  procedure SetAutoScroll(const Value: Boolean);
  procedure SetSeparatorH(const Value: Boolean);
  procedure SetSeparatorV(const Value: Boolean);
  procedure SetViewData(const Value: Boolean);
public
  constructor Create;
  destructor Destroy; override;
  property AutoScroll: Boolean read GetAutoScroll write SetAutoScroll;
  property SeparatorH: Boolean read GetSeparatorH write SetSeparatorH;
  property SeparatorV: Boolean read GetSeparatorV write SetSeparatorV;
  property ViewData: Boolean read GetViewData write SetViewData;
  property Column: TDictionary<String, TColumn> read fColumn write fColumn;
end;
...
FPythonModule_TerminalLog := TPythonModule.Create(nil);
FPythonModule_TerminalLog.Name := 'FPythonModule_TerminalLog';
FPythonModule_TerminalLog.Engine := FEngine;
FPythonModule_TerminalLog.ModuleName := 'terminal_log';
FPythonModule_TerminalLog.OnInitialization := OnInitialization_TerminalLog;
FPythonModule_TerminalLog.OnAfterInitialization := OnAfterInitialization_TerminalLog;
...
FPythonVersion.AssignTo(FEngine);
FEngine.LoadDll;
...  
terminalLogSettings := TTerminalLogSettings.Create;
pTerminalLogSettings := FPythonWrapper.Wrap(terminalLogSettings, soOwned);
FPythonModule_TerminalLog.SetVar( 'settings', pTerminalLogSettings);
FEngine.Py_DecRef(pTerminalLogSettings);
 
FPythonWrapper.RegisterDelphiWrapper(TColumnWrapper).Initialize;
FPythonWrapper.RegisterDelphiWrapper(TPyClassWrapper<TDictionary<string, TColumn>>).Initialize;
...

if used in this way in the script, then after the script finishes I correctly call the TTerminalLogSettings destructor and free the memory

...
iqrfide.terminal_log.settings.autoScroll = True
...

settings_object = iqrfide.terminal_log.settings
setattr(settings_object, 'autoScroll', True)
...

If the script is interrupted using exit(), the destructor is not called and the memory is not freed. Any explanation?

...
iqrfide.terminal_log.settings.autoScroll = True
...

settings_object = iqrfide.terminal_log.settings
setattr(settings_object, 'autoScroll', True)

exit()
...

Putting settings_object = None before exit solves the problem.

Share this post


Link to post

The exit() function raises a SystemExit exception and if it is not handled it shuts down python.  Don't use it in P4D scripts.

Share this post


Link to post

Hi, not using exit() is not the solution for me. Users use exit() when debugging a script.

If to ProcessSystemExit; i add Py_DecRef(errtraceback); so the memory leak problem will disappear. The destructor TTerminalLogSettings will already be called. I have no idea, but how is that possible.

procedure TPythonEngine.CheckError(ACatchStopEx : Boolean = False);
  procedure ProcessSystemExit;
  var
    errtype, errvalue, errtraceback: PPyObject;
    SErrValue: string;
  begin
    PyErr_Fetch(errtype, errvalue, errtraceback);
    Traceback.Refresh(errtraceback);
    SErrValue := PyObjectAsString(errvalue);
    Py_DecRef(errtraceback);      // workaround
    PyErr_Clear;
    raise EPySystemExit.CreateResFmt(@SPyExcSystemError, [SErrValue]);
  end;

 

  • Thanks 1

Share this post


Link to post
Posted (edited)

@iqrfYou are absolutely right,  PyErr_Fetch returns new references and clears the error. The code in ProcessSystemExit has now been fixed.  Thanks!

Edited by pyscripter

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×