Re: Tracking the retain count
Re: Tracking the retain count
- Subject: Re: Tracking the retain count
- From: Quincey Morris <email@hidden>
- Date: Tue, 19 May 2015 03:59:19 +0000
Let me try and summarize where we are, in response to the several recent suggestions:
Britt has an app with an existing, fully functional custom cache of objects that have a UUID property, with the restriction that UUIDs are unique amongst objects in the cache. Objects may be created in various incarnations over time under the same UUID, but only one incarnation can be in the cache using the UUID at any moment.
In addition, because of the overhead of managing the uniqueness of the UUIDs, it’s too expensive to create new objects regularly on demand. The purpose of the cache is to extend the lifetime of otherwise unreferenced objects so that they can be reused rather than reincarnated. It does this by taking ownership of (retaining, keeping a strong reference to, however you want to think of it) every object in the cache.
This means that objects can exist in memory in one of these states:
— “Referenced". That is, there is a strong reference to the object somewhere else in the app’s object graph, beyond the cache’s owning reference.
— “Unreferenced". There is no strong reference to the object elsewhere in the app’s object graph. The only “known-for-sure” strong reference is the cache’s owning reference. Britt originally wanted to believe that this meant that the cache contained the only strong reference, period, but I called this out as invalid reasoning about retain counts, because there’s actually a 3rd case …
— “Inaccessible". There is a reference to the object somewhere else for some other housekeeping reason. The prime such housekeeping reason is being in the autorelease pool pending draining, but in theory objects may perhaps temporarily be referenced somewhere in the bowels of the frameworks. (This has to be temporary, otherwise these objects would be leaked, but the point of deallocation is theoretically unknown.)
I don’t have any other plausible housekeeping reasons, but I do know that “No one else should be using this object right now” is a common prelude to a self-inflicted injury.
Now, Britt wants to modify the cache so that is capable of discarding all unreferenced objects. Discarding the sole owning reference would have this effect, but it would also destroy the cache itself, so that’s not feasible.
The easiest solution to conceptualize is to give the cache both a strong (owning) and a weak reference to each object. Then, to purge the cache of unreferenced objects, all that’s necessary is to nil the strong references. Thereafter the unreferenced objects will, we hope, become deallocated, though some may remain merely inaccessible. In particular, any objects referred to by an autorelease pool won’t get deallocated until the pool is drained. Once that’s done, as far as the app’s concerned there should be no more inaccessible objects, but in reality we don’t know this for sure — vid. "housekeeping reasons" — and we have no valid way of *reasoning* them out of existence.
Still, armed with a belief that most if not all are deallocated, it’s now possible to re-establish the strong references in the cache, and things go along as before until the next time the cache needs to be purged.
All of this is non-controversial. The problem is solved. Except that Britt isn’t happy with the duplication of resources involved in that solution.
So, I’ve been trying to sell the idea that you only need one pointer — the weak one — and that the full effect of the strong pointer can be obtained by merely incrementing the retain count (once) when an object enters the cache. To purge the cache, decrement all the retain counts, drain the autorelease pools, then increment them again. There are a couple of ways of doing this in an ARC environment, but I (in a similar situation) use CFRetain (or perhaps CFBridgingRetain, can’t remember) because I’ve found it most readable.
Britt’s hesitant about this solution, too, because it apparently reasons about retain counts, which we’re told not to do, and I seem to have just finished saying so too. I claim that there’s no contradiction. It’s valid in this situation, because the only reasoning we’re doing is about *our* ownership reference, not about any others that we don’t control. Indeed, we’re not so much reasoning, as relying on the definition of ownership.
On May 18, 2015, at 17:27 , Graham Cox <email@hidden> wrote:
>
> just pointing you at NSDiscardableContent for a second, that has a “pseudo-retain count” type of mechanism
I believe this is functionally identical to incrementing the actual retain counts, so it’d be a matter of personal preference which to use.
On May 18, 2015, at 17:48 , Roland King <email@hidden> wrote:
>
> Perhaps I missed something germane in the discussion about why a simple scheme like that doesn’t fulfil all requirements.
Just that Britt wanted to avoid having two sets of pointers.
On May 18, 2015, at 19:46 , email@hidden wrote:
>
> if you've got so many objects that it is causing memory pressure
I think the memory pressure we’re talking about here is something like a low-memory warning because *other* apps are trying to use all the memory and we’re trying to be helpful. We’re not really talking about the case where the cache itself is absolutely too big.
[Apologies for the length of this post.]
_______________________________________________
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