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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to