[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Re: Problem with KCompTreeNode on Windows (or: destruction order of static objects?)
From:       Milian Wolff <mail () milianw ! de>
Date:       2013-12-04 15:36:12
Message-ID: 2163115.GQ8o8SuM9j () milian-kdab2
[Download RAW message or body]

On Wednesday 04 December 2013 16:01:03 Frank Reininghaus wrote:
> Hi,
> 
> 2013/11/30 Kevin Funk:
> > Hey guys,
> > 
> > My recent attempts to make KDevelop shine on Windows revealed some odd
> > behaviour inside kdelibs.
> > 
> > I need some help in order to find the right approach to fix an at least 3
> > year old bug [1] ultimately caused by the use of a static member object
> > in the KCompTreeNode class (kcompletion.h) in kdelibs. Please see the
> > attached bug report [2].
> > 
> > Note that the error *only shows up on Windows*, on Linux we don't have
> > this
> > problem. I'll try to explain what's wrong in this mail.
> > 
> > The actual issue:
> > - KDevelop running:
> > - We have an instance of KateGlobal owned by KateFactory,
> > 
> >   a plugin loaded by KDevelop
> > 
> > - Some descendant of KateGlobal (KateCmd) owns a KCompTreeNode instance
> > - KCompTreeNode uses a custom allocator for creating/deleting instances
> > 
> >   of itself, holds a static member of type KZoneAllocactor for that
> > 
> > - KZoneAllocator holds the memory for all the instantiated KCompTreeNodes
> > 
> > So we have the following object ownership (some levels omitted):
> > - KateFactory
> > 
> >     KateGlobal
> >     
> >       KCompTreeNode
> >       
> >         KZoneAllocator (static)
> > 
> > When closing KDevelop *under Linux*:
> > - ~KateFactory, via QObjectCleanupHandler during __run_exit_handlers
> > (glibc)> 
> >     ~KateGlobal, via call to KateGlobal::decRef()
> >     
> >       ~KCompTreeNode
> > 
> > - ~KZoneAllocator, during __cxa__finalize (glibc)
> > 
> > The order is fine in this case. No segfaults.
> > 
> > However, on Windows the destruction order is different (and I cannot
> > really
> > explain why). When closing KDevelop *under Windows*:
> > - ~KZoneAllocator is called first, via
> > 
> >         "kdeui.dll!`dynamic atexit destructor for
> >         'KCompTreeNode::alloc''()"
> > 
> > - ~KateFactory, via QObjectCleanupHandler
> > 
> >     ~KateGlobal
> >     
> >       Call to KCompTreeNode::removeItem()
> > 
> > => Crash because memory for the KCompTreeNode instances was already freed
> > 
> >    by ~KZoneAllocator
> > 
> > I wonder how to fix that:
> > The easiest solution obviously: Get rid off the custom allocator in
> > KCompTreeNode. Having a class owning its custom allocator is just plain
> > wrong, right? But removing that probably has performance impacts. (Does
> > anyone have benchmarks here?)
> 
> well, having a custom allocator may have some benefits. I guess that
> KCompletion uses one to ensure that all KCompTreeNodes are close to
> each other in memory and thus to reduce cache misses? I don't know how
> much dropping the custom allocator would affect the performance, one
> would have to do some benchmarking with typical KCompletion use cases.

I agree that it might be a good performance improvement. But I want to note 
neither KDevelop nore Kate uses this technique for its code completion in the 
editor. And we probably have much more completion tree nodes than a usual 
KCompletion user. I just mention this to show that removing this performance 
improvement should not kill the performance, rather decrease it slightly.

> > Just using K_GLOBAL_STATIC for the KZoneAllocator instance doesn't help
> > either. I get the same destruction order + crash with that on Windows.
> > 
> > Dynamic allocation inside KCompTreeNode doesn't work either, because
> > KZoneAllocator needs to be there *before* the first KCompTreeNode is
> > created and needs to there *until* the last one has been destroyed.
> > 
> > Any ideas?
> 
> Well, here is one idea (untested): use a
> QSharedPointer<KZoneAllocator> to ensure that the KZoneAllocator is
> not destroyed before the last KCompletion instance using it.
> 
> Replace
> 
> static KZoneAllocator alloc;
> 
> in KCompTreeNode by
> 
> static QSharedPointer<KZoneAllocator> alloc;
> 
> and, in kcompletion.cpp,
> 
> KZoneAllocator KCompTreeNode::alloc(8192);
> 
> by
> 
> QSharedPointer<KZoneAllocator> KCompTreeNode::alloc;
> 
> In KCompTreeNode's operator new/delete, replace "alloc." by "alloc->".
> 
> Furthermore, add a QSharedPointer<KZoneAllocator> member to
> KCompletionPrivate. In KCompletionPrivate's constructor, first check
> if KCompTreeNode::alloc isNull(), initialize it if that is not the
> case, and then copy "alloc" to the new member.
> 
> I think that this might work, and it might also improve application
> start-up time because the KZoneAllocator would only be initialized on
> first use of a KCompletion object.

Yes, that might work. Kevin, could you try it out?

Bye
-- 
Milian Wolff
mail@milianw.de
http://milianw.de

>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic