Will an interface-implementing form free itself when there are no more references to it? - delphi

If I implement an interface on a form such as TMyForm = class(TForm, IMyInterface), will the object free itself when there are no more interface references to it? It seems not to, although I couldn't work out how TForm is reference counted (if at all). I'm concerned about the form getting freed when an interface reference goes out of scope, but this does not seem to happen.
I guess there are two parts to the question, firstly whether a form might get unexpectedly freed (the real question), and secondly how forms are reference counted.

TForm derives from TComponent, which implements _AddRef() and _Release() to disable reference counting on itself. As such, any interface implemented by any TComponent descendant class, like TForm, will not free its implementing TComponent object by default when the interface is released.
However, if an IVCLComObject interface is assigned to the TComponent.VCLCOMObject property, then TComponent will delegate reference counting to that object, so that object can be freed if its reference count falls to 0 (TComponent does not increment the reference count of its IVCLCOMObject reference).
This is valid for all descendants of TComponent, unless they implement any reference counting of their own by overriding _AddRef() and _Release() manually.

IF you implement an interface in a form, it can be worth adding your own
_Release as follows:
function _Release: Integer; stdcall;
function TMyInterfacedForm._Release: Integer;
begin
result:=-1;
end;
I found that it was possible to free a form with an interface, and then have the _Release called as the local variable went out of scope. This could produce an access violation, as the Tcomponent implementation checks to see if FVCLComObject is set
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._Release;
Since at this stage, FVCLComobject is undefined, an annoying A/V exception can occur.
By hardwiring the -1, it can be called safely without trigger exceptions.

Related

Is this a bug in System.Net.HttpClient on Rio?

This is the function found in Delphi Rio in System.Net.HttpClient
THTTPClientHelper = class helper for THTTPClient
....
procedure THTTPClientHelper.SetExt(const Value);
var
{$IFDEF AUTOREFCOUNT}
LRelease: Boolean;
{$ENDIF}
LExt: THTTPClientExt;
begin
if FHTTPClientList = nil then
Exit;
TMonitor.Enter(FHTTPClientList);
try
{$IFDEF AUTOREFCOUNT}
LRelease := not FHTTPClientList.ContainsKey(Self);
{$ENDIF}
LExt := THTTPClientExt(Value);
FHTTPClientList.AddOrSetValue(Self, LExt);
{$IFDEF AUTOREFCOUNT}
if LRelease then __ObjRelease;
{$ENDIF}
finally
TMonitor.Exit(FHTTPClientList);
end;
end;
What the guy try to do with LRelease here?
{$IFDEF AUTOREFCOUNT}
LRelease := not FHTTPClientList.ContainsKey(Self);
{$ENDIF}
LExt := THTTPClientExt(Value);
FHTTPClientList.AddOrSetValue(Self, LExt);
{$IFDEF AUTOREFCOUNT}
if LRelease then __ObjRelease;
{$ENDIF}
So if FHTTPClientList doesn't contain the THTTPClient add it in the FHTTPClientList and then reduce it's refcount by one. Why reduce it's refcount by one?? the THTTPClient is still alive and used why breaking it's refcount? Their is a bug here, maybe the guy make a typo, but i don't understand what he want to do originally ...
for info this this how items are removing from the dictionary :
procedure THTTPClientHelper.RemoveExt;
begin
if FHTTPClientList = nil then
Exit;
TMonitor.Enter(FHTTPClientList);
try
FHTTPClientList.Remove(Self);
finally
TMonitor.Exit(FHTTPClientList);
end;
end;
Purpose of the manual reference counting for ARC compiler in above code is simulating dictionary with weak references. Delphi generic collections are backed with generic arrays that will hold strong reference to any object added to the collection on ARC compiler.
There is several ways to achieve weak references - using pointers, using wrappers around object where object is declared as weak and manual reference counting in appropriate places.
With pointers you lose type safety, wrappers require significantly more code, so I guess the author of above code opted for manual reference counting. Nothing wrong with that part.
However, as you noticed, there is something fishy in that code - while SetExt routine is written properly RemoveExt has a bug resulting in a crash later on.
Let's go through the code in context on ARC compiler (I will omit compiler directives and unrelated code for brevity):
Since adding object into collection (array) increases reference count, to achieve weak reference we have to decrease reference count of the added object instance - that way the instance's reference count will remain the same after it is stored in collection. Next, when we remove object from such collection, we have to restore reference count balance and increase reference count. Also we have to make sure that object will be removed from such collection before it is destroyed - good place to do that is destructor.
Adding to collection:
LRelease := not FHTTPClientList.ContainsKey(Self);
FHTTPClientList.AddOrSetValue(Self, LExt);
if LRelease then __ObjRelease;
We add the object to the collection and then after collection holds strong reference to our object we can release it's reference count. If object is already inside collection that means it's reference count was already decreased and we must not decrease it again - that is the purpose of LRelease flag.
Removing from collection:
if FHTTPClientList.ContainsKey(Self) then
begin
__ObjAddRef;
FHTTPClientList.Remove(Self);
end;
If object is in collection we have to restore the balance and increase the reference count before removing object from collection. This is the part that is missing from RemoveExt method.
Making sure that object is not in the list upon destruction:
destructor THTTPClient.Destroy;
begin
RemoveExt;
inherited;
end;
Note: In order for such faked weak collection to work properly items must be added and removed only through above methods that take care of balancing reference count. Using any other original collection methods like Clear will result in broken reference count.
Bug or not?
In System.Net.HttpClient code broken RemoveExt method is called only in destructor, also FHTTPClientList is private variable and it is not altered in any other way. On the first glimpse, that code works properly, but actually contains rather subtle bug.
To unravel the real bug we need to cover possible usage scenarios, starting with few established facts:
Only methods that alter content and by that reference count of items in FHTTPClientList dictionary are SetExt and RemoveExt methods
SetExt method is correct
Broken RemoveExt method that does not call __ObjAddRef is called only in THTTPClient destructor and this is where this subtle bug originates.
When destructor is called upon any particular object instance that means object instance has reached it's lifetime, and any subsequent reference counting triggers (during destructor execution) have no influence on the code correctness.
That is ensured by applying objDestroyingFlag on FRefCount variable changing its value and any further count increasing/decreasing can no longer result in special value 0 that starts destruction process - so object is safe and will not get destroyed twice.
In above code when THTTPClient destructor is called that means last strong reference to object instance has gone out of scope or was set to nil and at that moment the only remaining live reference that can trigger reference counting mechanism is the one in FHTTPClientList. That reference has been cleared by RemoveExt method (broken or not) at that point as previously said it does not matter. And everything works fine.
But, author of the code has forgotten one tiny weeny thingy - DisposeOf method that triggers the destructor, but at that point object instance has not reached its reference counting lifetime. In other words - if destructor is called by DisposeOf, any subsequent reference counting triggers must be balanced because there are still live references to the object that will trigger reference counting mechanism after the destructor chain calls are completed. If we break the counting at that point result will be catastrophic.
Since THTTPClient is not TComponent descendant that requires DisposeOf it is easy to make the oversight and forget that someone, somewhere could call DipsoseOf on such variable anyway - for instance if you make owned list of THTTPClient instances clearing such list will call DisposeOf on them and happily break their reference count because RemoveExt method is ultimately broken.
Conclusion: Yes, it is a BUG.

Memory management of interfaces in Delphi

I am struggling to learn delphi and memory management, coming from C#.
The current incarnation of that struggle is that I don't know the right way to dispose of the objects when I am done with them. From reading and my experiments it seems that if I have an object that is cast as an interface, then my ONLY choice is set the reference to nil.
If I go an call
FreeAndNil()
I end up getting an access violation, EX:
var
foo: IFoo;
begin
foo := TFoo.Create();
FreeandNil(foo);
end;
Sure, all I need to do it change that foo:IFoo; to foo:TFoo; and it is happy. OR simply set the pointer to nil, NOT call freeandNil.
foo := nil;
So, on one level, I don't understand in the least where the AV is.
On a differently level, I want to write the code such that it does not need to know if it is an interface or an object. I want to be able to write all of my memory management the same exact way, but I can't seem to write a method that can deal with something that is a Class or an interface. Well, that is not true, I do have something, but it is so ugly I hesitate to post it.
But I guess I should also be asking, what is everyone else doing? Mentally keeping track of what is an interface and just nil those pointers? otherwise calling FreeAndNil?
I am going to want to implement things the first time around as a concrete class, but later come back and change that to an interface when I find some way that the code can do from 2 different ways. And I am not going to want to go through the code and change how it was dealing with that reference, that is the last thing on my mind at that point.
But for the sake of discussion, the best (almost only) idea I have is this class:
interface
type
TMemory = class(TObject)
class procedure Free(item: TObject); overload; static;
class procedure Free<T: IInterface>(item: T); overload; static;
end;
implementation
uses
System.SysUtils;
{ TMemory }
class procedure TMemory.Free(item: TObject);
begin
FreeandNil(item);
end;
class procedure TMemory.Free<T>(item: T);
begin
//don't do anything, it is up the caller to always nil after calling.
end;
Then I can consistently call:
TMemory.Free(Thing);
Thing := nil;
Test code:
procedure TDoSomething.MyWorker;
var
foo: IFoo;
fooAsClass: TFoo;
JustAnObject: TObject;
begin
foo := TFoo.Create();
fooAsClass := TFoo.Create();
JustAnObject := TObject.Create();
TMemory.Free(foo);
foo := nil;
TMemory.Free(fooAsClass);
fooAsClass := nil;
TMemory.Free(JustAnObject);
JustAnObject := nil;
end;
runs with no leaks or access violations. (using MadExcept)
But a big thank you to the Delphi community on SO. You guys have been the best thing out there for learning!
The reason for the access violation is that FreeAndNil takes an untyped parameter, but expects it to be an object. So the method operates on the object.
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj); //Obj must be a TObject otherwise all bets are off
Pointer(Obj) := nil; //Will throw an AV if memory violation is detected
Temp.Free; //Will throw an AV if memory violation is detected
end;
A memory violation in the above might (NB not guaranteed) be detected if you destroy an object that has either been previously destroyed or never created. It's also likely to be detected if Obj doesn't reference an object at all but something else (such as an interface, record, Integer because these don't implement Free and if they did, it wouldn't be located in the same way as TObject.Free).
On a differently level, I want to write the code such that it does not need to know if it is an interface or an object. I want to be able to write all of my memory management the same exact way.
This is like saying you want to use your car in exactly the same way that you use your shower.
Ok, maybe the difference is not quite that extreme. But the point is that interfaces and objects (and for that matter records) use different memory management paradigms. You cannot manage their memory in the same way.
Objects need to be explicitly destroyed. You can use an ownership model, but destruction is still an explicit external action.
Interfaces are reference counted. The compiler injects code to track the number of fields and variables referencing (looking at) the underlying instance. Typically the object destroys itself when the last reference is released. (There are ways beyond the scope of this answer to change this.)
If we access some object by interface variable, it doesn't always mean that object is destroyed the moment reference counter drops to zero. For example, TComponent methods _AddRef and _Release implementations are 'dummy': no reference counting is implemented and TComponent is never destroyed because interface variables are out of scope.
To behave as we expect from 'real' interfaces, all your objects should be descendants from TInterfacedObject or you need to implement _AddRef / _Release yourself.
Yes, there are 2 different approaches to memory management which usually co-exist in a program, but confusion (and AV) arises only when the same object is treated in both ways. If we destroyed object and only then the interface variables have gone out of scope, they call _Release method of destroyed object which causes access violation. That's some risky business, though with some attention it is doable.
Classic Delphi components are not reference-counted, the concept of ownership is used instead. Each component has an owner whose responsibility is to free all the memory when it itself is destroyed. So each component has an owner, but it may also have a lot of pointers to another components, like when Toolbar has ImageList variable. If such components were refcounted, they would never be destroyed because of circular reference, so in order to break this circle you'd need 'weak' references as well which don't 'count'. They are here, too, but that's very recent feature of Delphi.
If there is some hierarchy in your objects, so you know that 'bigger' objects need all of 'smaller' ones to function, then use this good old approach, it's pretty simple and has very good implementation in Delphi, which is: you can make a code which will be leak-free no matter where exception could arise. There are all these little things like using .Free instead of .Destroy, because if exception happened in constructor, destructor is called automatically, and so on. Very clever solution in fact.
I'd use refcounted interfaces only if you don't know for how long some object is needed for you and there is no suitable 'owner' for it. I did it with scanned image which I saved to file in one thread, while converting to smaller image to show on screen on another thread. When all is done, image is no more needed in RAM and can be destroyed, but I have no idea which happens first. In this case using refcounting is best thing to do.

What does the Free() method actually do internally and how does it handle object references?

Question
In the code below a new object of type TStringList is created and passed to a procedure which is using that object. By passing the object to the method ProcToFillStringList a new object reference is created by coping the reference. My questions regarding this code are:
What happens to the object reference stored in the parameter SList
after the method returns? Does it remove the reference to the object
from the stack?
What does the Free() method actually do internally? Does it remove all references to the object from the stack or does it remove
the object itself? Which references are removed?
Do object references (not the object itself) get removed from stack automatically when a method returns?
Would it be better to pass the reference byref?
Code
var
SL: TStringList; // first object reference
begin
SL := TStringList.Create; // creating object
try
ProcToFillStringList(SL);
finally
SL.Free; // -> what gets 'freed' here? the object? the references? both?
end;
end;
procedure ProcToFillStringList(const SList: TStrings); // second object reference
SList.Add('x'); // not calling Free -> does the reference get removed?
end;
Here is code of Free method on newer versions of Delphi:
procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
if Self <> nil then
Destroy;
{$ENDIF}
end;
There are two different cases. When compiled to environment with automatic reference counting (that is iOS), Free doesn't work at all, objects are freed only when the last reference to them is removed (but as said in comments to code above, compiler changes your SL.Free to SL:=nil, so if it was the last reference to object, it will be freed and SL is really set to nil.
But in all other platforms objects are not reference counted. When calling Free, object memory is freed, but your variable is not set automatically to nil (not saying about another variables pointing to the same object), that's just impossible with syntax like this. Any method of object can't change variable it's called from. That's why you write SL := TStringList.Create instead of SL.Create. In first case you get new memory address where object is created and assign SL to it. In second SL is not initialized and can point anywhere, so there is no way to create object exactly there.
So, to answer your questions:
Object reference in local procedure is removed when it goes beyond the scope. But if you use const or var argument, it is not created in the first place. Actually, you're using the same reference SL here.
In iOS Free does nothing, object will be destroyed automatically when SL variable goes beyond the scope. In other platforms, Free destroys object and doesn't affect other references at all.
Yes, they do.
Use that modifier which describes your situation best. Const will tell compiler and people working with your code (including yourself) that argument won't be changed in procedure, compiler may pass it by value (for objects less than pointer) or by reference, but no matter what it chooses, refcount will never be increased, so from this point of view, you can think that you use exactly the same object, like it was passed by reference.
Using Var (by reference) you can accidentally change the variable you passed to procedure and this makes your intentions unclear, so use it only when you really want to change this variable and Const otherwise.
In the documentation of embarcadero is written
System::TObject::Free automatically calls the destructor if the object reference is not nil
It means in your case that the object SL is cleared at the point you called SL.Free. A object inherited from TObject does not know how many references are alive to that instance. Only the pointer to the address of the instance of SL is passed to the function call ProcToFillStringList. The instance is not informed about the new reference.
If you want to handle reference counting have a look at TInterfacedObject and the 3 Methods
QueryInterface
_AddRef
_Release
a new object reference is created by coping the reference
New reference const SList is just non-changeable pointer to the object. It will be removed from the stack if it lives there (in this case parameter is passed through register).
Free doesn't clear any references. It just destructs an object, frees it's memory. There is 'FreeAndNil' routine that frees object and makes one reference nil. Other references still exist.

Why do interface implementations based on TComponent leak memory?

This Delphi code will show a memory leak for an instance of TMyImplementation:
program LeakTest;
uses
Classes;
type
MyInterface = interface
end;
TMyImplementation = class(TComponent, MyInterface)
end;
TMyContainer = class(TObject)
private
FInt: MyInterface;
public
property Impl: MyInterface read FInt write FInt;
end;
var
C: TMyContainer;
begin
ReportMemoryLeaksOnShutdown := True;
C := TMyContainer.Create;
C.Impl := TMyImplementation.Create(nil);
C.Free;
end.
If TComponent is replaced by TInterfacedObject and the constructor changed to Create(), the leak disappears. What is different with TComponent here?
Many thanks for the answers. To sum up: it is easy, but wrong, to say "If you are using interfaces, they are reference counted and hence they are freed for you." - Actually any class which implements an interface can break this rule. (And there will be no compiler hint or warning be shown.)
Differences in implementation
TComponent._Release does not free your instance.
TInterfacedObject._Release does free your instance.
Perhaps someone can chime in but my take on this is that TComponent is not meant to be used as a reference counted object the way we normally use interfaces.
Implementation of TComponent._Release
function TComponent._Release: Integer;
begin
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._Release;
end;
TComponent doesn't implement its _AddRef and _Release methods the same as TInterfacedObject does. It defers its reference counting to its VCLComObject property, which should be some other interfaced object. Since TComponent doesn't count references, it can't detect when its reference count reaches zero, so it doesn't free itself.
The VCLComObject property holds an interface reference, which should implement IVCLComObject. If a component's associated VCLComObject object has been told that it owns the component, then when that interface's reference count reaches zero, it will destroy its associated component. It's told it owns the component by calling its FreeOnRelease method.
All this is designed to make it easier to wrap VCL components into COM objects. If that's not your goal, then you'll probably be fighting against several other unexpected design aspects along the way, so you might wish to re-evaluate your motivation for making your components implement interfaces in the first place.
A component is supposed to be owned and destroyed by something else, typically a form. In that scenario, reference count is not used. If you pass a component as an interface reference it would be very unfortunate if it was destroyed when the method returns.
Therefore, reference counting in TComponent has been removed.

why aren't descendants of TInterfacedObject garbage collected?

i have a class based on TInterfacedObject. i add it to TTreeNode's Data property.
TFacilityTreeItem=class(TInterfacedObject)
private
m_guidItem:TGUID;
m_SomeOtherNode:TTreeNode;
public
end;
i create many instances of this object & had assumed that because they're reference counted, i shouldn't need to Free them. that'd be handy.
however, when checking this, i turned on ReportMemoryLeaksOnShutdown and found they're not being freed after all.
these objects are being created in a frame that's placed on the main form. in the main form's FormClose, i clear the tree nodes such that every object should be freed.
what's happening?
thank you for your help!
TInterfacedObject itself is not reference counted, only interfaces are. You can implement interfaces using TInterfacedObject which basically saves you the effort of implementing the reference counting methods yourself. Unfortunately it still will not work in your case: The compiler does not know that you are assigning interfaces to the TTreeNode.Data property since it is not declared as an interface but as a pointer. So all kinds of weird things will happen:
MyInt := TFacilityTreeItem.Create; // ref count = 1
// Node.Data := MyInt; // won't compile
Node.Data := pointer(MyInt); // no interface assignment, ref count stays 1
...
end; // ref count reaches 0, your object gets freed
As soon as you try to access your object through the .Data property, you will get an access violation.
So, don't bother with interfaces in this case, you could get it to work, but it will be much more effort than it is worth.
You should declare the Field/Variable as Interface
IFacilityTreeItem = IInterface
end;
TFacilityTreeItem=class(TInterfacedObject, IFacilityTreeItem)
private
m_guidItem:TGUID;
m_SomeOtherNode:TTreeNode;
end;
var
Item: IFacilityTreeItem; // Variable as Interface
begin
Item:= TFacilityTreeItem.Create;
...
end;
To access your fields, you should declare properties in IFacilityTreeItem Interface, with Getters and Setters.
As dummzeuch said, you can get this to work with interfaces, but it takes some more code since the Data property of a TTreeNode is a pointer. For anyone wondering how to do that, this link has an example of how to do it for TListItem (it's pretty much the same for TTreeNode). You may also find it useful to read the section about interfaces and subsequent section about reference counting on that page.

Resources