Re: Tracking the retain count
Re: Tracking the retain count
- Subject: Re: Tracking the retain count
- From: Britt Durbrow <email@hidden>
- Date: Wed, 20 May 2015 01:41:58 -0700
In no particular order:
> On May 19, 2015, at 8:37 PM, Graham Cox <email@hidden> wrote:
>
> I think what the OP says he wants is that the cache can only release when it knows nobody else has a reference to an object as well, hence the temptation to peek at the retain count. In other words it must be the “last owner”, for some reason.
Yes, exactly: the reason being that of maintaining graph coherency.
Suppose we have these objects in play:
The object pool controller, call it OPC.
A view controller, call it VC1.
Another view controller, call it VC2.
A document model object in the pool controlled by OPC, call it DMO1 (and lets say it’s got a UUID of 12345, cuz’ ya know, that’s the combination on my luggage ;-)
The view controller VC1 has a strong reference to DMO1
A memory pressure event occurs, and OPC decides to evict DMO1, but it doesn’t immediately go away, because VC1 is holding on to it.
VC2 comes along and wants to get at the object with UUID 12345 (in order to execute [someObject stealAllTheAir], lets say).
Sooo… OPC loads the data for UUID 12345 from file storage, alloc’s a new object (call it DMO2), sets it’s parameters (including assigning the UUID to it), puts it in the in-RAM object pool, and returns the new object as being the object for UUID12345. Note that this can often happen as a result of a fault firing, so VC2 didn’t even know it was asking for UUID 12345, just that it was messaging a pointer to some object.
So, at this point, in RAM there is: OPC (who knows DMO2 as UUID 12345), VC1 (who knows DMO1 as 12345), VC2 (who knows DMO2 as 12345), DMO1 (who thinks it is UUID 12345), and DMO2 (who also thinks it is UUID 12345).
And now VC1 is writing to DMO1, thinking it’s updating UUID 12345, at the same time as VC2 is doing the same thing to DMO2, also thinking it’s talking to UUID 12345.
BOOM, loss of graph coherency.
Now, if OPC knows that there is somebody out there with a strong link to DMO1, it won’t evict that object (instead, it’ll pick some other object to get rid of that only it has a strong link to), and when VC2 comes along an tries to access something that’s supposed to be UUID 12345, it gets the same object that everybody else thinks is UUID 12345, because there was only ever one in RAM at any given time that had UUID 12345.
And that’s just one scenario… the possible permutations of not maintaining UUID-identity are vast (I speak from experience on this one - the early development versions of the engine had all sorts of hiccups)...
> On May 19, 2015, at 3:50 PM, Graham Cox <email@hidden> wrote:
> Instead, if objects that access the cached objects are forced to use ‘beginContentAccess’ and ‘endContentAccess’ then you have a very definite way to find out when nobody is accessing the objects that cannot be interfered with by memory management in any way.
>
> I may have misunderstood the problem such that this is a poor ot for other reasons, but I’m not seeing it. I’m also not sure why there seems to be a tacit resistance to it - seems logical to me.
>
> —Graham.
I don’t think that NSDiscardableContent was intended to be used in *quite* that way; but even not using NSDiscardableContent and coming up with my own protocol to do that has a problem: there is an existing body of code that I really don’t want to have to try to retrofit that onto, as I would have to track down each and every access and bracket it; and I’m basically back to all the pitfalls of project-wide manual retain counting. Instead, I’m trying to have the object pool controller do all the work in a centralized location.
> I think the problem is that Britt is conflating two semantically distinct things: whether the object exists, and whether the object is “in use”. S/he is attempting to determine that the object is not “in use” while it still exists by peeking at retainCount to see if it’s 1.
I’m deliberately conflating that, because if it exists in the object pool controller’s strong container with a retain count of anything greater than 1, it *could* be in use, and therefore is not safe to evict from the in RAM object pool. Yes, this reasoning (which I’m *not* wedded to, as it were) does make some assumptions, but I do believe that they are backed up by the runtime documentation: that there is only one retain count, and that that retain count is accessed thru -retainCount, and that attempting to access an object that you don’t have a retain on is illegal.
Note that this is *exclusionary* logic, not *inclusionary* logic: nothing else can be inferred from the retain count; only that *something* has it.
That said, I’ve done some testing, and although NSMutableDictionary was performing substantially worse than I expected in terms of memory footprint, NSMapTable with weak links was not performing as badly as I expected either in terms of memory or CPU time… but I *think* I can make it work well enough to solve the problem using a combination of the non-retainCount approaches discussed on this thread (some explicit retains, some bitfield magic on some otherwise unused bits in the object’s 'headers', and some interlocking with the fault-firing mechanism).
P.s. - It’s a ‘he’ - I’m a big dude with a beard. :-)
>
> On May 19, 2015, at 11:26 PM, Jonathan Hull <email@hidden> wrote:
>
> You still have to be really careful about threading here.
FWIW, the object pool is not guaranteed thread-safe.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden