Re: How do I debug an autorelease crash?
Re: How do I debug an autorelease crash?
- Subject: Re: How do I debug an autorelease crash?
- From: publiclook <email@hidden>
- Date: Sun, 14 Sep 2003 11:02:55 -0400
On Saturday, September 13, 2003, at 11:07 AM, Dave Riggle wrote:
I got all my code wired together yesterday, which means my problem
could be anywhere. Is there an easy way to track down the culprit? I
crash with a signal 11 here:
0 objc_msgSend
1 NSPopAutoreleasePool
2 -[NSApplication run]
3 NSApplicationMain
4 main
What exactly causes this crash anyway? Have I manually released an
autoreleased object? It seems like it would be more useful to get a
signal raised at the time of the error rather than at the end of the
run loop.
Your theory is most probably correct. The first way to avoid these
problems is to follow Cocoa's very simple conventions for memory
management. See copious threads on the subject in this forum by
searching with mamasam:
http://cocoa.mamasam.com/. See
http://www.stepwise.com/Articles/Technical/2001-03-11.01.html and many
similar articles at stepwise
http://www.stepwise.com/StartingPoint/Cocoa.html.
After you have made a mistake, it is actually not that hard to figure
out what went wrong. See NSDebug.h
Here are some handy environment variables that you can set or specify
on the command line:
NAME OF ENV. VARIABLE DEFAULT SET TO...
NSDebugEnabled NO "YES"
NSZombieEnabled NO "YES"
// Enable object zombies. When an object is deallocated, its isa
// pointer is modified to be that of a "zombie" class (whether or
// not the storage is then freed can be controlled by the
// NSDeallocateZombies variable). Messages sent to the zombie
// object cause logged messages and can be broken on in a debugger.
// The default is NO.
NSDeallocateZombies NO "YES"
// Determines whether the storage of objects that have been
// "zombified" is then freed or not. The default value (NO)
// is most suitable for debugging messages sent to zombie
// objects. And since the memory is never freed, storage
// allocated to an object will never be reused, either (which
// is sometimes useful otherwise).
NSHangOnUncaughtException NO "YES"
NSEnableAutoreleasePool YES "NO"
NSAutoreleaseFreedObjectCheckEnabled NO "YES"
As you might guess from these variables, running your application with
the following arguments will enable you to zero in on the problem:
-NSDebugEnabled YES -NSZombieEnabled YES
-NSAutoreleaseFreedObjectCheckEnabled YES
Then, when an attempt is made to release and already deallocated object
(such as when you leave pointers to deallocated objects in an
autorelease pool), an exception is raised. The exception identifies
the object that was over released. That object will be an NSZombie
that you can interrogate to determine what class the original object
was. You can also configure the autorelease pools to never release the
objects they contain and you can configure objects so that they are
never deallocated. When a release message is sent that would have been
sent to a deallocated object if the object had been permitted to be
deallocated, an exception is raised and you can see in the debugger
exactly which -release was one -release too many.
Some handy methods and functions of the NSAutoreleasePool class:
// Functions used as interesting breakpoints in a debugger
FOUNDATION_EXPORT void _NSAutoreleaseNoPool(void *object);
// Called to log the "Object X of class Y autoreleased with no
// pool in place - just leaking" message.
FOUNDATION_EXPORT void _NSAutoreleaseFreedObject(void *freedObject);
// Called when a previously freed object would be released
// by an autorelease pool. See +enableFreedObjectCheck: below.
FOUNDATION_EXPORT void _NSAutoreleaseHighWaterLog(unsigned int count);
// Called whenever a high water mark is reached by a pool.
// See +setPoolCountHighWaterMark: below.
@interface NSAutoreleasePool (NSAutoreleasePoolDebugging)
+ (void)enableRelease:(BOOL)enable;
// Enables or disables autorelease pools; that is, whether or
// not the autorelease pools send the -release message to their
// objects when each pool is released. This message affects only
// the pools of the autorelease pool stack of the current thread
// (and any future pools in that thread). The "default default"
// value can be set in the initial environment when a program
// is launched with the NSEnableAutoreleasePool environment
// variable (see notes at the top of this file) -- as thread
// pool-stacks are created, they take their initial enabled
// state from that environment variable.
+ (void)showPools;
// Displays to stderr the state of the current thread's
// autorelease pool stack.
+ (void)resetTotalAutoreleasedObjects;
+ (unsigned)totalAutoreleasedObjects;
// Returns the number of objects autoreleased (in ALL threads,
// currently) since the counter was last reset to zero with
// +resetTotalAutoreleasedObjects.
+ (void)enableFreedObjectCheck:(BOOL)enable;
// Enables or disables freed-object checking for the pool stack
// of the current thread (and any future pools in that thread).
// When enabled, an autorelease pool will call the function
// _NSAutoreleaseFreedObject() when it is about to attempt to
// release an object that the runtime has marked as freed (and
// then it doesn't attempt to send -release to the freed storage).
// The pointer to the freed storage is passed to that function.
// The "default default" value can be set in the initial
// environment when a program is launched with the
// NSAutoreleaseFreedObjectCheckEnabled environment variable
// (see notes at the top of this file) -- as thread pool-stacks
// are created, they take their initial freed-object-check state
// from that environment variable.
Some more interesting stuff in NSDebug.h:
FOUNDATION_EXPORT BOOL NSHangOnMallocError;
// MACH only: Cause the process to hang after printing out the
// "Malloc-related error detected with code N" message to stderr.
// A backtrace can be gotten from the process with the 'sample'
// utility, or the process can be attached to with a debugger.
// The default is NO. Has no effect on non-MACH platforms.
FOUNDATION_EXPORT BOOL NSHangOnUncaughtException;
// If set to YES, causes the process to hang after logging the
// "*** Uncaught exception:" message. A backtrace can be gotten
// from the process with the 'sample' utility, or the process can
// be attached to with a debugger. The default is NO.
FOUNDATION_EXPORT BOOL NSIsFreedObject(id anObject);
// Returns YES if the value passed as the parameter is a pointer
// to a freed object. Note that memory allocation packages will
// eventually reuse freed memory blocks to satisfy a request.
// NSZombieEnabled and NSDeallocateZombies can be used to prevent
// reuse of allocated objects.
/**************** Stack processing ****************/
FOUNDATION_EXPORT void *NSFrameAddress(unsigned frame);
FOUNDATION_EXPORT void *NSReturnAddress(unsigned frame);
// Returns the value of the frame pointer or return address,
// respectively, of the specified frame. Frames are numbered
// sequentially, with the "current" frame being zero, the
// previous frame being 1, etc. The current frame is the
// frame in which either of these functions is called. For
// example, NSReturnAddress(0) returns an address near where
// this function was called, NSReturnAddress(1) returns the
// address to which control will return when current frame
// exits, etc. If the requested frame does not exist, then
// NULL is returned. The behavior of these functions is
// undefined in the presence of code which has been compiled
// without frame pointers.
FOUNDATION_EXPORT unsigned NSCountFrames(void);
// Returns the number of call frames on the stack. The behavior
// of this functions is undefined in the presence of code which
// has been compiled without frame pointers.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.