舉例來說:
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSData* data = [NSData dataWithBytes:"asklaskdxjgr" length:12]; [data release]; [pool release];由於NSData的dataWithBytes是類方法,並且會設置autorelease,所以在pool釋放內存的時候,data已經是殭屍對象.
解決方法來說一般也是2個,第一個所有對象都使用autorelease方式,但是這種方式的問題在於performance不怎麼好,而且也不利於程序員水平的提高.第二個就是找到殭屍對象,查看其調用關係,理順內存釋放順序.那麼找到殭屍對象就成爲了急需解決的問題.
蘋果有個頭文件,叫NSDebug.h,具體在這裏. 很久以前就是靠引入這個頭文件來解決問題.當然隨着obj-c 2.0的引入,我們可以不再用這麼古老的方式.新的做法如下:
1 在xode裏右擊可執行文件,選擇get info-->arguments-->Variables to be set in the ENV
2 添加以下變量
NSDebugEnabled NSZombieEnabled MallocStackLogging MallocStackLoggingNoCompact ?設置他們的值爲YES. 3 在debug模式下運行程序,到pool release的時候,會在console上看到: 2010-12-25 08:01:38.644 autoreleasebug[3939] *** *** Selector 'release' sent to dealloced instance 0xa4e10 of class NSConcreteData. 這就說明有殭屍對象出現,給了進程id--3939,對象內存地址--0xa4e10. 4 接下來在console裏敲shell malloc_history pid(3939) address(0xa4e10).得到調用關係如下: Call [2] [arg=24]: thread_a000a1ec |0x0 | _dyld_start | _start | main | NSApplicationMain | -[NSApplication run] | -[NSApplication sendEvent:] | -[NSWindow sendEvent:] | -[NSControl mouseDown:] | -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] | -[NSCell trackMouse:inRect:ofView:untilMouseUp:] | -[NSCell _sendActionFrom:] | -[NSControl sendAction:to:] | -[NSApplication sendAction:to:from:] | -[MEController newCity:] | -[MECityEditor editCity:otherCities:] | -[NSApplication runModalForWindow:] | -[NSApplication _realDoModalLoop:peek:] | -[NSApplication nextEventMatchingMask: untilDate:inMode:dequeue:] | _DPSNextEvent | BlockUntilNextEventMatchingListInMode | ReceiveNextEventCommon | RunCurrentEventLoopInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoObservers | _handleWindowNeedsDisplay | -[NSWindow displayIfNeeded] | -[NSView displayIfNeeded] | -[NSView _displayRectIgnoringOpacity: isVisibleRect:rectIsVisibleRectForView:] | -[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView: topView:] | -[NSFrameView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect: rectIsVisibleRectForView:topView:] | -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity: isVisibleRect:rectIsVisibleRectForView:topView:] | -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] | -[NSView(NSInternal) _getDirtyRects:clippedToRect:count:boundingBox:] | -[NSRegion mutableCopy] | NSAllocateObject | _internal_class_createInstanceFromZone | malloc_zone_ca lloc 根據這個調用關係,我們就可以哪個對象被提前釋放了,從而修改程序.