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.
Related
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.
I'm new to interfaces and have been trying them out in my latest project. I have this (simplified) interface:
IBoardShape = interface(IInterface)
function GetColor: integer;
procedure SetColor(const aColor: integer);
property Color: integer read GetColor write SetColor;
end;
Several classes descend from it like so:
TGameRectangle = class(TRectangle, IBoardShape)
private
FColor: integer;
function GetColor: integer;
procedure SetColor(const aColor: integer);
property Color: integer read GetColor write SetColor;
end;
I have a factory for creating the shapes in its own data module.
function TdmShapeManager.CreateRect(aParent: TLayout): IBoardShape;
var
lRect: TGameRectangle;
begin
lRect := TGameRectangle.Create(self);
lRect.Parent := aParent;
lRect.Align := TAlignLayout.alClient;
result := lRect as IBoardShape;
end;
The result is added to a TList<IBoardShape>.
All of this worked well, until I started trying to remove shapes at run time. I found that TList[I] := nil didn't free the item, the control would just stay on the screen. So, from here I'm not sure to do. I found I can cast the object to a TShape and call .Free on it, but that doesn't sound right. (I tried it and it works but then it leads to other problems - errors inside Delphi code when trying to free an interface.)
One thing that I'm not sure about: Since my TGameRectangle doesn't descend from TInterfacedObject, should I be doing my own reference counting? Or am I misunderstanding what TInterfacedObject is for?
I'm going to restrict my answer to desktop platforms which do not have ARC. That's because on ARC platforms there is nothing to do. The ARC framework will manage lifetime for you and you must not re-implement _AddRef and _Release.
For non-ARC platforms you have a fundamental design problem. You want your object's lifetime to be controlled by two independent mechanisms:
The TComponent owner, and
The interface reference count.
You need to make up your mind to do it one way or the other. But not both.
If you opt for the first option you just need to make sure that you clear the interface reference before the owner is destroyed. Then let the owner destroy your rectangle object.
If you opt for the second option you need to pass nil as the owner parameter of the constructor. And then implement interface reference counted lifetime management as per TInterfacedObject.
A common pattern is to let the value of the owner passed to the constructor determine the lifetime model. So, when the owner is nil, interface reference counting controls the life. Otherwise the owner controls it. The canonical example of this pattern is TXMLDocument.
All that said, I don't think this pattern works at well with visual components. The framework is designed so that visual component lifetime is not controlled by interface reference counting. I think it is folly to go against that design. I suggest you opt for option 1.
Yes, if you want to use interfaces and reference counting, you need to either inherit from a type that provides reference counting or provide your own implementations of _AddRef and _Release.
What do the _AddRef and _Release that your TGameRectangle has do?
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.
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.
I have a small problem with interfaces. Here it is in Pseudo code :
type
Interface1 = interface
end;
Interface2 = interface
end;
TParentClass = class(TInterfacedObject, Interface1)
private
fChild : Interface2;
public
procedure AddChild(aChild : Interface2);
end;
TChildClass = class(TInterfacedObject, Interface2)
private
fParent : Interface2;
public
constructor Create(aPArent : Interface1);
end;
Can anyone see the flaw? I need the child to have a reference to it's parent, but the reference counting doesn't work in this situation. If I create a ParentClass instance, and add a child, then the parent class is never released. I can see why. How do I get round it?
A reference-counted reference has two semantics: it acts as a share of ownership as well as a means of navigating the object graph.
Typically, you don't need both of these semantics on all links in a cycle in the graph of references. Perhaps only parents own children, and not the other way around? If that is the case, you can make the child references to the parent weak links, by storing them as pointers, like this:
TChildClass = class(TInterfacedObject, Interface2)
private
fParent : Pointer;
function GetParent: Interface1;
public
constructor Create(aPArent : Interface1);
property Parent: Interface1 read GetParent;
end;
function TChildClass.GetParent: Interface1;
begin
Result := Interface1(fParent);
end;
constructor TChildClass.Create(AParent: Interface1);
begin
fParent := Pointer(AParent);
end;
This is safe if the root of the tree of instances is guaranteed to be kept alive somewhere, i.e. you are not relying on only keeping a reference to a branch of the tree and still being able to navigate the whole of it.
Well, the reference counting of course does work in this situation - it just doesn't solve the problem.
That's the biggest problem with reference counting - when you have a circular reference, you have to explicitely 'break' it (set one interface reference to 'nil', for example). That's also why reference counting is not really a replacement for garbage collection - garbage collectors are aware that cycles may exist and can release such cyclic structures when they are not referenced from the 'outside'.
You must make a method that explicitly unlinks the right references. There is no way to get the automatic reference counting working properly in this case.
With the use of a function pointer in the first example then the cyclic reference problem doesn't exist. .NET uses delegates, and VB6 uses events. All of which have the benefit of not incrementing the reference count of the object being pointed too.