Re: Threads + Garbage Collection = Crash?
Re: Threads + Garbage Collection = Crash?
- Subject: Re: Threads + Garbage Collection = Crash?
- From: Bill Bumgarner <email@hidden>
- Date: Thu, 02 Oct 2008 10:24:41 -0700
On Oct 1, 2008, at 5:35 AM, Oleg Krupnov wrote:
In my application, I create a (single) background thread, for creating
thumbnail images. I use NSRunLoop and - [NSObject
performSelector:onThread:withObject:waitUntilDone:] to communicate
between the main and the background threads.
I am experiencing weird random crashes with the following log:
IconView(49550,0xb0103000) malloc: free_garbage: garbage ptr =
0x1239260, has non-zero refcount = 1
IconView(49550,0xb0103000) malloc: *** free() called with 0x1bdcf6b0
with refcount 0
IconView(49550,0xb0103000) malloc: *** auto malloc[49550]: agc error
for object 0x1bdcf6b0: Deallocating a non-block
Turn on malloc_history (see the malloc man page) and then grab a
history of all allocation events at address 0x1bdcf6b0. Most likely
(in your case, not all cases), whatever object was last at 0x1bdcf6b0
is the one that is being freed early.
My application relies heavily on garbage collection (the gc required
mode), so I never call malloc/free explicitly. I don't create
NSAutoreleasePool in the background thread's main method.
To verify:
- you are creating the thread via NSThread?
- you are running a Run Loop in said thread?
That should be sufficient to make the collector aware of the thread.
If you were spinning up a pthread and doing your own cross-thread
communication via the pthread synchronization primitives, then you
would need to call [NSThread currentThread] from that thread to make
the collector aware of the thread.
I set breakpoint on malloc_printf and I see the following stack trace:
malloc_printf
autocollect_internal
autocollection_thread
_pthread_start
thread_start.
I have noticed that these crashes occur more often when the workload
is high - i.e. there are many sequential requests to the background
thread.
Likely, simply a catalyst to failure. Under high load, there will be
more objects created and destroyed. As such, the collector will be
busier. As well, whatever race condition is causing the issue -- and
it is a race condition, given the intermittent nature of the crasher
-- is more likely to happen when more stuff is happening in your app,
especially stuff that causes variation in thread scheduling.
Also, I have located a piece of code in the main thread such that when
I comment it out, the crash disappears, although the code fragment has
absolutely nothing to do with the background thread. It actually fills
a round rect with a gradient fill, in the main thread. Funny enough,
when the rect is square, not round, the bug also disappears.
Aha! When you are filling that rect, you are likely causing the main
thread's stack to go fairly deep as the thread passes through the
rendering machinery. And a round rect likely goes deeper than a
square rect because of the extra math involved.
How is that significant?
It most likely indicates that the object being reaped too early by the
collector is only being kept alive by the main thread's stack and,
then, only inadvertently.
So:
- are you passing references to hunks of memory on the stack between
threads?
- are you using NSInvocation? It doesn't correctly retain its
arguments under GC. You'll want to keep references to arguments in
some other container.
- are you storing pointers into malloc()'d memory or other places
where the collector might not see them? If so, either don't or use
CFRetain/CFRelease on the pointers that land outside of the
collector's zone.
b.bum
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________
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