views:

22

answers:

2

In my code I'm instantiating a legacy Delphi object through a COM interface. This class needs to be instantiated many times, so in order to lower the overhead of instantiating it I cache it at a point where 70% of all the calls have the common resulting object.

However, when I alter the object after it is cached, the changes are persisted in the cache too. This makes me think the COM wrapper instance is passed by ref instead of by value.
How can I make sure that the object in cache is passed by value rather then by ref?

A: 

I think that, if it's possible to do at all, you need to explicitly clone a copy of the object and then cache the copy. See for example the MemberwiseClone method, and others mentioned in answers to Cloning objects in C#.

ChrisW
That's what I feared :S
borisCallens
I'm not even sure MemberwiseClone will work as intended on COM objects. It could **at best** clone public properties, but not any internal state mutated through methods.
peterchen
Yes I think that at best it will clone the wrapper, and not clone the actual COM object which is being wrapped.
ChrisW
The object has an "exportToXml" and "importFromXml" they are relatively expensive though, but I think I'm out of alternatives.
borisCallens
A: 

First, is this needed?

I'm not an advocate of "measuring solve all performance problems", but in your case, you should.

The overhead of instantiating a COM object (after the first call penalty) as such is very low - remember it was designed to afford many small objects on computers of 15 years ago. I assume the .NET overhead isn't much more - so the question is the objects own initialization.

You can check that easily by instantiating 1000 objects in a tight loop (throw away the first call, it can be very expensive and would spoil the average)

COM objects are inherently by reference
There is no "pass by value" for COM objects, as their basic interface is a reference counted pointer to the instance, and COM doesn't expose a generic "Clone" method.

possible solution: Copy-on-Write
If an only if instantiation is really expensive, and the majority of calls can be done through a default instance, you can implement a copy-on-write scheme.

You need to create a wrapper class that holds a reference to the default instance, and a reference to a private instance initialized to 0.

As long as the private instance is null, all getter functions forward to the default instance, otherwis, they forward to the private instance.

Every setter/mutator call forwards to the private instance, creating it when it doesn't exist.

This would delay creation for the private instance to the first mutating call. However, you have to wrap the entire all interfaces of interest for this component.

peterchen
Thanks for your reminder regarding "premature optimization is the devil". I am aware of the principle of measuring. In my case it is not as much the instantiation that is costly, but the initialization (getting a bunch of DB values inserting them in the object and triggering logic internal to the object). This initialization is performed several times per request and several thousand requests are made per minute per site. As performance analysis (Ants) have pointed out this is currently (even with the caching) the bottleneck of the entire app. I will consider implementing your final suggestion
borisCallens
Furthermore the legacy logic of the application doesn't allow me to review the application's design to evade the repeated initialization except for caching.
borisCallens
Boris, I see this as a legit reason to invest - even if it's only to remove the "failure point" of accessing the DB.
peterchen