#1 2012-06-19 10:09:28

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Circular reference and zeroing weak pointers

The memory allocation model of the Delphi interface type uses some kind of Automatic Reference Counting (ARC).
In order to avoid memory and resource leaks and potential random errors in the applications (aka the terrible EAccessViolation exception on customer side) when using interfaces, a SOA framework like mORMot has to offer so-called Weak pointers and Zeroing Weak pointers features.

Note that garbage collector based languages (like Java or C#) do not suffer from this problem, since the circular references are handled by their memory model: objects lifetime are maintained globally by the memory manager. Of course, it will increase memory use, slowdown the process due to additional actions during allocation and assignments (all objects and their references have to be maintained in internal lists), and may slow down the application when garbage collector enters in action. In order to avoid such issues when performance matters, experts tend to pre-allocate and re-use objects: this is one common limitation of this memory model, and why Delphi is still a good candidate (like unmanaged C or C++) when it deals with performance and stability.

Forum thread for our blog article http://blog.synopse.info/post/2012/06/1 … k-pointers

Offline

#2 2012-06-20 05:45:10

TPrami
Member
Registered: 2010-07-06
Posts: 105

Re: Circular reference and zeroing weak pointers

Hello,

Would it be possiblöe to refactor this functuionality out on some Commons unit. To it's own entity, so it would be more usable in programs that might not use mORMot wink

There are some cool stuff in mORMot, but could kind of publish some of the stuff in it's on entities, so they would be easy to use in app that will not use the rest of the library. Mainly the problem is that the unit name would not tell the other programmers the reaon why this mysterious SynSqliteMormotCommonsGlobalUtils.pas is included in the uses clause wink

Just my 0.02€ wink

-Tee-

Offline

#3 2012-06-20 09:00:30

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Circular reference and zeroing weak pointers

I had the same exact discussion with Stefan at http://delphisorcery.blogspot.fr/2012/0 … 7562971175

You could change the vmtAutoTable trick into a more "standard" hash-based global list, containing all TSetWeakZeroClass instances. So the FreeInstance hook on class level will continue to work as expected - and I suspect this is a path to follow, for the lowest possible performance penalty on the application (using a global hook is IMHO far from efficient). Having such TSetWeakZeroClass per-class instances sounded like a good pattern, also for speed and memory use.

Note that you can nest vmtAutoTable references, if needed. Therefore, existing code that make use of "Hallvards excellent hack" is compatible with this implementation (not SOLID, but possible). For instance, in mORMot we already used this VMT slot to access pre-compiled RTTI at class level for the ORM part of the framework. And it is compatible with the TSetWeakZeroClass use: you can create a zeroing weak pointer for an interface implemented by a ORM class. In fact, this is the reason why our SetWeak/SetWeakZero functions are included within the main unit of the framework, not the more generic SynCommons.pas file. So that's why I was not afraid of re-using the same vmtAutoTable hack, since it is already used by our framework.

I think it could be easily extracted from mORMot, then ported to x64 and OSX. All pointer arithmetic is already using PtrInt (=NativeInt), and will work even with FPC. In its current implementation, it is tied to mORMot, but it is on purpose. It was not meant to be used stand-alone, but as part of the framework.

So you are right about those implementation restrictions, there are on purpose. And of course, they do not match every one expectations!

I just hope ideas and implementation patterns could be inspiring, and be adapter to every need!

So in short, it could be done, you are encouraged to do it if you need, but I prefer make it part of mORMot by now.
Delivering stand-alone tricks tends to be difficult to maintain, and AFAIR other such low level stand-alone trick I published (like the RecordCopy) was not used much.
Feel free to publish whatever derived work from this small piece of code!

Offline

#4 2012-06-22 12:11:36

Leander007
Member
From: Slovenia
Registered: 2011-04-29
Posts: 113

Re: Circular reference and zeroing weak pointers

This code (direct casting of interface to TObject):

{$ifdef UNICODE}
    result := aValue as TObject; // slower but always working
{$else}

from SQLite3Commons.pas at

function ObjectFromInterface(const aValue: IInterface): TObject;

does not compile for Delphi 2009.

See at this stackoverflow issue.
The user said that Hallvard's hack was not working with him, but I tested your hack with Delphi 2009 and it seems that it works, so the define should be changed for Delphi 2009 as it is for older Delphi compilers.

Last edited by Leander007 (2012-06-22 12:47:18)


"Uncertainty in science: There no doubt exist natural laws, but once this fine reason of ours was corrupted, it corrupted everything.", Blaise Pascal

Offline

#5 2012-06-23 06:01:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Circular reference and zeroing weak pointers

Nice catch.

Should be fixed with http://synopse.info/fossil/info/ce734bb138

I've also updated the StackOverflow question.

Offline

#6 2012-10-23 15:28:23

Bascy
Member
From: The Netherlands
Registered: 2012-06-22
Posts: 108

Re: Circular reference and zeroing weak pointers

How can i use this SetWeakZero if I have a TDictionary<integer, IInterface> as i need some reference to the Interfacefield and TDictionary.AddOrSetValue....

Offline

#7 2021-07-08 07:32:29

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Circular reference and zeroing weak pointers

Just encapsulate the TDictionary inside an class/interface.

BTW in mORMot 2, we introduced interface-based collections and a convenient (and faster/enhanced) IKeyValue dictionary in https://github.com/synopse/mORMot2/blob … ctions.pas

Note that mORMot 2 also features SetWeak/SetWeakZero functions, with a new implementation.

Offline

Board footer

Powered by FluxBB