gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Unresolved Issues with libxml2


From: Doug Simons
Subject: Re: Unresolved Issues with libxml2
Date: Sat, 3 Mar 2012 12:00:55 -0700

Hello Fred,

That's a very interesting idea -- and perhaps you've already implemented it 
(I've been busy with some issues with releasing our software so wasn't able to 
find the time to respond sooner). And if this is how Cocoa does it then perhaps 
it is what GNUstep should do, but I'm not entirely happy with the idea.

I don't entirely like it because I believe it creates the potential for some 
rather odd and potentially unexpected (and undesirable) behavior, although 
perhaps not all that likely in practice. But please indulge me for a moment, if 
only so that I can justify to myself the rather considerable effort that I put 
into making the current (possibly overly-complex) scheme work. ;-)

Imagine a scenario where an NSXMLDocument is created (by parsing an XML 
document, let's say) and retained by an object that we'll call Ancestor. 
Another object, Son, is created that references (and retains) one of the 
NSXMLElements that is a descendant somewhere further down in the tree. Ancestor 
and Son are used and accessed in various places in the application. At any 
time, Son is able to access its Parent node, and from there can gain access to 
any of Parent's other children -- Son's siblings. 

Now, at some point in time every object in the application with a direct 
reference to Ancestor is released, causing Ancestor to be fully released and 
(under the scheme you're proposing) deallocated. Suddenly and without warning, 
through no action of its own, Son is detached and made an orphan, with no 
parent, and no way to access its siblings even though some of them may already 
be instantiated as Obj-C objects, which are now similarly orphaned.

Perhaps that's not the most likely scenario, but I don't think it's entirely 
far-fetched. The only solution I see for such a scenario is for the application 
author to have Son keep and retain a reference to Ancestor for as long as Son 
is around -- but then you've suddenly created exactly the kind of retain loop 
between Son and Ancestor that the current NSXMLNode memory management scheme 
goes to great lengths to resolve, so it will all "just work" for the 
application developer.

Under the current scheme, as long as the application holds a retain on any 
Obj-C object anywhere in the tree, the entire underlying tree structure and any 
other Obj-C objects that have been instantiated as part of it are kept in 
memory. When the final "external" (from outside of the tree) retain is 
released, the entire structure and all of the objects are freed. A fair bit of 
complexity internal to the framework to make using the framework simple.

So I'm disappointed to hear that Cocoa does it the cheap way! I appreciate that 
that approach will be simpler to implement and easier to understand the 
internal GNUstep code, but I wonder if it would be at all worthwhile at this 
point to allow a "WholeTreeIntegrity" flag to enable a developer to choose 
either memory behavior. Any thoughts?

Cheers,

Doug

On Mar 2, 2012, at 10:06 AM, Fred Kiefer wrote:

> On 01.03.2012 11:08, Richard Frith-Macdonald wrote:
>> 
>> Agreed.  In particular we need a lot of tests to run on Apple systems
>> to find out exactly how their object ownership model works.  What
>> happens when you create documents and then release them while holding
>> references to various nodes within them?  Does behaviour vary
>> depending on how documents are created?  What about standalone nodes
>> without documents?  What about namespaces?!!
> 
> It turns out that things are a lot simpler than we thought. I wrote a few 
> tests on Cocoa and nothing of that mysterious behaviour that we tried to 
> mimic showed up. It looks like Apple implemented a simple top down approach. 
> The parent retains the child and nothing more. And we had even test code that 
> took advantage of that behaviour, see basic.m in NSXMLNode:
> 
>    NSXMLElement *node = [[NSXMLElement alloc] initWithKind: NSXMLElementKind];
>    NSXMLDocument *docA = [[NSXMLDocument alloc] initWithRootElement: node];
>    NSXMLDocument *docB = nil;
>    // NSLog(@"Here...");
>    [node detach];
>    PASS(docB = [[NSXMLDocument alloc] initWithRootElement: node], "Detached 
> children can be reattached.");
>    [docA release];
>    // NSLog(@"Here... again");
>    [docB release]; <-- HERE
>    docA = [[NSXMLDocument alloc] initWithRootElement: node];
>    // NSLog(@"Yet again");
>    PASS_EXCEPTION(docB = [[NSXMLDocument alloc] initWithRootElement: node], 
> NSInternalInconsistencyException, "Reusing a child throws an exception");
> 
> Did you spot the release on the document docB? This make the node usable 
> again, that is node no longer has a parent and may be used as a root element 
> in docA. I added a few tests that prove this behaviour. After the release of 
> docB parent of node is nil!
> This could be implemented rather easily by detaching all subnodes of any 
> deallocated node. The only clever bit needed here is to make sure we free up 
> the libxml2 nodes that don't have corresponding Objective-C objects, but I 
> think that will happen automatically if we free the libxml2 node after 
> detaching all the subnodes. There may be a few cases where this behaviour is 
> slightly slower, but it is a lot more consistent than the current code.
> Any objections? Otherwise I go ahead and implement this.
> 
> 
> _______________________________________________
> Gnustep-dev mailing list
> address@hidden
> https://lists.gnu.org/mailman/listinfo/gnustep-dev
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]