Re: Deadlock during NSCache flush
Re: Deadlock during NSCache flush
- Subject: Re: Deadlock during NSCache flush
- From: ChanMaxthon <email@hidden>
- Date: Tue, 22 Oct 2013 09:57:26 +0800
Can you just manually retain it before cleaning, and manually release it afterwards? You can use CFRetain()/CFRelease() for that, or use runtime functions objc_retain() and objc_release(). The latter two is not documented by Apple per sé, but it is documented by LLVM as requirements of ARC.
Sent from my iPhone
> On 2013年10月22日, at 3:11, Jens Alfke <email@hidden> wrote:
>
> I’ve just gotten a nasty bug report involving an iOS app hanging when it goes into the background. The problem is a deadlock involving NSCache. I can see what the problem is, but I don’t know what to do about it.
>
> In a nutshell: An NSCache is evicting objects, and as a result of that its last reference goes away so the cache gets dealloced. Only the dealloc method needs the same (non-recursive) lock the eviction call is using, so it deadlocks.
>
> Specifically, there is a “database” object that has a strong reference to an NSCache which maps to various ‘document’ objects (indexed by key.) The document objects have strong references back to the database.
>
> In the situation that hangs, there is a database with one document, neither of which have any external strong references to them. (They probably used to at one point, but the app stopped using that database.) That’s fine, it’s not a reference cycle because the NSCache will get cleaned up. Only the cleanup doesn’t work because:
>
> 1. OS tells NSCache to flush value objects (`cache_remove_with_block`)
> 2. NSCache releases the document, causing it to be dealloced
> 3. Document’s dealloc implicitly releases its reference to the database
> 4. Database is released and dealloced, implicitly releasing the NSCache
> 5. NSCache is dealloced … but the `cache_destroy` call needs the mutex that’s already being held by `cache_remove_with_block`.
>
> (You can see the full backtrace in the bug report on github.)
>
> Has anyone else run into this? Is there a workaround? This has come up once before for me, and I was able to work around it by making the cache-owner object call -autorelease instead of -release on the NSCache, to defer the call to the cache’s dealloc. But I’m now using ARC so that isn’t an option.
>
> ―Jens
> _______________________________________________
>
> 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
_______________________________________________
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