#1 2017-08-21 14:36:17

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Interfaced object being dumped from memory

Hi Ab,

We have a weird one. We're trying to use the DI feature where we inject an instance of a configuration reader to our service using ServiceContainer.RegisterGlobal and we ran across a very strange issue.

Sample code here (with all Synopse code removed to show a pure Delphi example):
https://stackoverflow.com/questions/457 … rom-memory

Anyone had to deal with something like this before?

Offline

#2 2017-08-21 14:50:22

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

Re: Interfaced object being dumped from memory

Use two variables: one for the class, and one for the interface.
Use the interface variable to manage the instance lifetime.
Don't call free, but set the interface variable to nil (or out of scope) to let the instance running.
Use the class variable to have direct raw access to the instance.

See my answer at https://stackoverflow.com/a/45800122/458259

Offline

#3 2017-08-22 07:39:48

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Interfaced object being dumped from memory

Thanks for the quick reply Ab. I am still curious as to why Delphi is exhibiting this behaviour. It's quite scary that it never called the destructor at all.

Offline

#4 2017-08-22 08:29:27

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Interfaced object being dumped from memory

Hi Ab,

Sad to say it doesn't work when calling registerGlobal. Some more digging and looking at Stefan Glienke's advice, we followed the code and looking BeforeDestruction we came to the following conclusion:
In RegisterGlobal the code calls IInterface(aImplementation)._AddRef, but tries to free the implementation in FinalizeGlobalInterfaceResolution. This causes BeforeDestruction to raise an invalid pointer operation because the RefCount is not zero. Changing FinalizeGlobalInterfaceResolution's call from ImplementationInstance.Free to IInterface(ImplementationInstance)._Release, causes the issue to go away and no memory is leaked.

Offline

#5 2017-08-23 08:02:29

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

Re: Interfaced object being dumped from memory

To be honest, we don't use RegisterGlobal at all on our side.
In fact, global registration is not good Dependency Injection - it is a global variable in disguise...
Therefore, we only use context-specific resolution, either via injection at constructor level, or using late resolution with TInterfaceResolver.

So this part of the code seemed to have issues, as you discovered.
I feel sorry for that! sad

I also introduced several fixes and enhancements, including the fact that calling IInterface(aImplementation) is not safe on older versions of Delphi (not affecting you, I guess).
See https://synopse.info/fossil/info/e7744b86ff

Offline

#6 2017-08-25 10:25:46

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Interfaced object being dumped from memory

No problem, Ab. Thanks for the quick response.

We're only using it to get access to our config file at this stage, which we don't want to reload and re-parse for every instance of our Interface-based service. As we're not in control of when the implementation is constructed, we can't use constructor based injection to pass the instance of the config file. How are you handling this scenario?

Offline

#7 2017-08-25 10:43:35

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

Re: Interfaced object being dumped from memory

If you use such a global injection, you won't be able to have several instances of the same config file in the same process.
IMHO this is a weakness - perhaps not now, but in the future, or if you want to run several of such services in a single executable, e.g. for testing purposes.

It is not difficult to inject the configuration file at service constructor level, for instance.
No need to load and parse it for each instance: keep it at the service level, then resolve it at instance level.

Offline

Board footer

Powered by FluxBB