Re: Leaks in nsSessionStore.js?

"Michael Vincent van Rantwijk, MultiZilla" <[email protected]> Fri, 16 Nov 2007 18:56:06 +0100
Newsgroups gmane.comp.mozilla.performance
Message-ID <[email protected]>
Jeff Walden wrote:
> Michael Vincent van Rantwijk, MultiZilla wrote:
>> http://lxr.mozilla.org/seamonkey/source/browser/components/sessionstore/src/nsSessionStore.js#177 
> 
> 
> Note the third parameter is |true|.  Looking at the IDL:
> 
>> If set to false, the nsIObserverService will hold a strong reference 
>> to |anObserver|. If set to true and |anObserver| supports the 
>> nsIWeakReference interface, a weak reference will be held. Otherwise 
>> an error will be returned.
> 
> The idea of a weak reference is that you don't increment the refcount -- 
> you create an object which stores a pointer to whatever it is you want 
> and return it instead.  Given that object, you call QueryReferent(iid) 
> on it to get a strong reference, which only then increments the 
> pointer.  The key to keeping this pointer from going stale on you is 
> that when the actual object dies, its destructor will null out the 
> pointer in the object you hold, so you can't use the dead pointer.  One 
> other thing to note is that you only ever need one weak reference object 
> no matter how many places might want one, so if you need a weak 
> reference, you can be given the existing one.
> 
> The details are in 
> <http://mxr.mozilla.org/mozilla/source/xpcom/glue/nsWeakReference.cpp>; 
> I highly recommend spending half an hour or so reading it and figuring 
> out how it works for the "aha!" moment you'll have.
> 
> Anyway, back to the question: the call says |this| implements 
> nsISupportsWeakReference.  In C++ this would just be by inheriting from 
> nsSupportsWeakReference, and in JS it's by having a QueryInterface which 
> returns |this| when the provided IID is nsISupportsWeakReference.  Since 
> we have the latter, XPConnect will make the wrapper implement 
> nsISupportsWeakReference, and if that wrapper goes away because its 
> refcount reaches zero, it'll clear the pointer stored in the one weak 
> reference the prefbranch has, and since the prefbranch thus no longer 
> has a pointer, no cycle occurs.
> 
> This is all a bit confusing, but I'm not sure there's really a good way 
> to explain it -- you just need to stare at it for awhile until it makes 
> sense.
> 
> Jeff

Thanks you so much Jeff,

First, I now understand that the weak versus strong reference is about 
owning it, and having a proxy for the object, presumably saving memory 
and speeding things up a few milliseconds.

I was also able to convert my own XPCOM components to use weak 
references i.e. by using |true| as third parameter, and by adding:

   QueryInterface: function(aIID)
     if (aIID.equals(Ci.nsIMyService) ||
         aIID.equals(Ci.nsIObserver) ||
+       aIID.equals(Ci.nsISupportsWeakReference) ||
         aIID.equals(Ci.nsIProfileStartupListener) ||
         aIID.equals(Ci.nsISupports))
       return this;

However, what I still fail to understand is _when_ I should (must?) use 
weak references instead of a strong one; because most observers in the 
CVS tree seem to be using a strong reference.

Also, is it possible that I use a weak reference which somehow gets 
cleared, giving me a nsnull instead of a proxied object?

-- 
Michael Vincent van Rantwijk
- MultiZilla Project Team Lead
- XUL Boot Camp Staff member (ActiveState Training Partner)
- iPhone Application Developer