Re: Silly ARC question - explanation requested
Re: Silly ARC question - explanation requested
- Subject: Re: Silly ARC question - explanation requested
- From: Ken Thomases <email@hidden>
- Date: Wed, 04 Jun 2014 16:59:33 -0500
On Jun 4, 2014, at 4:26 PM, Alex Zavatone wrote:
> On Jun 4, 2014, at 4:07 PM, Ken Thomases wrote:
>
>> You have a misconception as illustrated in the above quotes. I think you think of ARC as a garbage collector that needs idle time or for execution to return to the frameworks in order to work. It is not and does not.
>>
>> For the most part, ARC just inserts retains and releases just as you would in manual retain-release mode if you were extremely careful. (The exception is weak pointers which get nil-ed out when the pointed-to object is deallocated. There's also the returned-autoreleased object optimization that you couldn't achieve on your own, but that's not relevant here.)
>
> I was jumping to that conclusion because I had never seen ARC code in a dispatch_async thread fail to release memory in low memory conditions.
ARC is not sensitive to memory conditions, just as the behavior of retains and releases you write in your code in MRR mode are not. ARC inserts retains and release at compile time.
> I'd never seen a situation where setting a variable to nil didn't release the memory under ARC before, let alone keeping every instance allocated even if I'd set it to nil.
Setting a strong reference to nil releases the prior referent. That reference may not have been the last one, so the object is not necessarily immediately deallocated. There's still retain counting going on, it's just behind the scenes.
An object that was retained and then autoreleased has not been released yet. The reference is, logically, in the autorelease pool. When that is drained, that's when the reference is released.
> Our call to the grayscale conversion would allocate 3.52 MB every time it was called and stored the UIImage in a local. Even if I tried to invalidate the image, nil the memory would never get released until after the while loop exited.
Either the UIImage or some large internal resource was presumably held in the autorelease pool.
> I made the while loop exit after 100 frames and our 172 MB of allocated RAM instantly hopped back down to 2.8 MB.
>
> Honestly, I'd expect that as the loop looped, the previous instance of the grayscale image would immediately be released, but somehow the while loop or the dispatch_async prevented this.
Again, if you're not draining an autorelease pool within your loop, objects can just accumulate in an outer pool indefinitely.
> I guess a better question is "why/how does the while loop seem to delay ARC's memory releasing, or was this caused by the while loop being inside a GCD dispatch?
The loop does not delay ARC's releasing. ARC is not responsible for the autorelease pool. ARC will autorelease objects that it has strong references to if they are returned out of the function/method, because that's necessary to keep them alive long enough for the caller to receive them. Likewise, it will autorelease objects returned through output parameters (e.g. NSError**), by default. In some cases, ARC can detect that the caller would immediately retain the object and it can cancel the autorelease and retain out, but that's just an optimization.
But objects which have been autoreleased, whether by MRR code or ARC code, are in an autorelease pool. ARC no longer has any effect on them. They will live until that pool is drained.
>> It sounds to me like this is just the classic sort of peak memory usage you would get with autoreleased objects with manual retain-release code if you don't drain the autorelease pool in your loops.
>
> So, while this feels to me at if it's encouraging this type of problem to pop up, it is acceptable practice, as long as the critical elements are in autorelease pools and are manually drained?
What is "it"?
> It just seems that a much better approach would be if the frame processing was one async thread for one frame at a time and was only called upon a frame change by watching hasNewPixelBufferForItemTime. Then when that frame thread is completed processing, execution isn't stuck in a while loop while being inside one large asynch-ly dispatched process.
Well, a "while (true)" loop is a pretty strong code smell. If that while loop is ever busy looping or sleeping, the smell is even worse. But it's completely separate from the issue of memory management. Do not decide whether to use such a loop based on the autorelease pool management. Decide on more fundamental design tenets. Is such a loop the right design for what your program is doing? (From the sound of things, I would guess it's probably not.)
Regards,
Ken
_______________________________________________
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