delphi - Why is an interface in the sub class not released -
i'm facing following situation , i'm wondering code leaking memory. let have following interfaces , implementations:
type itools = interface function helloworld : string; end; idatabase = interface function query(aquery : string) : string; end; imanager = interface procedure execute; end; tdatabase = class(tinterfacedobject, idatabase) strict private ftools : itools; public constructor create; destructor destroy; override; function query(aquery : string) : string; end; ttools = class(tinterfacedobject, itools) strict private fdatabase : idatabase; public constructor create(adatabase : idatabase); destructor destroy; override; function helloworld : string; end; tmanager = class(tinterfacedobject, imanager) strict private fdatabase : idatabase; public constructor create; procedure execute; end;
now, if create example this:
procedure example; var lexample : imanager; begin lexample := tmanager.create; lexample.execute; lexampe := nil; // should not necessary end;
where fdatabase
tmanager
created tdatabase
, passed in constructor of ttools
, has same (?) object / interface in ttools in tmanager. lexample
leaks memory, because of interfaces / objects in sub class (idatabase
). why isn't interface released? or don't understand of delphi fundamentals?
why isn't interface released?
you have circular reference.
tdatabase contains reference ttools , ttools contains reference tdatabase.
because delphi not have garbage collector not able resolve these circular references without help.
if using mobile nexgen compiler, or d10.1 berlin solution declare tdatabase as:
tdatabase = class(tinterfacedobject, idatabase) strict private [weak] <<-- ftools : itools; public constructor create; destructor destroy; override; function query(aquery : string) : string; end;
the [weak]
attribute trigger delphi generate different code when ftools
assigned. , runtime keep bookkeeping if reference count of interface goes 0 object not destroyed if weak reference happens not involved in circular reference.
marco cantù writes here: http://blog.marcocantu.com/blog/2016-april-weak-unsafe-interface-references.html
writes [unsafe]
attribute. don't use one, unless know means, it's not need.
you should mark 1 of circular references [weak]
! if mark both mishaps occur.
what if compiler not support [weak]
?
if using older delphi windows or osx targets solution follows.
use hack described by: http://blog.dummzeuch.de/2014/06/19/weak-references-or-why-you-should-enable-reportmemoryleaksonshutdown/
procedure setweak(_interfacefield: piinterface; const _value: iinterface); begin ppointer(_interfacefield)^ := pointer(_value); end; type tchild = class(tinterfacedobject, ichild) private fparent: iparent; // must weak reference! public constructor create(parent: iparent); destructor destroy; override; end; constructor tchild.create(parent: iparent); begin inherited create; setweak(@fparent, parent); end; destructor tchild.destroy; begin setweak(@fparent, nil); inherited; end;
what make reference in underhanded way reference count not go permanently.
not hack not have full protection against mishaps [weak]
attribute gives.
if weak reference happens not involved in circular reference might have premature destruction of fparent.
arnaud bouchez has more detailed write-up in blog; recommend read it: http://blog.synopse.info/post/2012/06/18/circular-reference-and-zeroing-weak-pointers
Comments
Post a Comment