使用xcode調試殭屍對象

在寫obj-c代碼的時候,殭屍對象是比較麻煩的問題.殭屍對象是指,提前釋放內存的對象.對於iphone/mac程序來說,出現這個問題的原因一般有 2個,第一,程序員自己過早釋放內存,第二,使用了外部框架導致的.第一點很容易查出來,第二點來說,主要是因爲外部框架一般會使用 autorelease,如果對框架怎麼運行不清楚的話,提前手動釋放內存,就會使自動釋放內存的時候出錯.
舉例來說:
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

根據這個調用關係,我們就可以哪個對象被提前釋放了,從而修改程序.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章