初級:第一步 為程序添加符號斷點 malloc_error_break 方法如下。
目標效果:讓程序崩潰時跳轉到出錯到那一行。但是往往達不到這個效果。不行就繼續往下看。
At times, while running through your app, you might come across this warning on console:
MyApp(2121,0xb0185000) malloc: *** error for object 0x1068310: double free
*** set a breakpoint in malloc_error_break to debug
Even though you might feel that its not affecting your app, but its still annoying, and might cause some memory related issues as well.
So before going ahead, what is the compiler actually trying to tell you?
Well, its pretty simple, it is trying to tell you that the object at the memory location 0×1068310 is being freed twice, and it is trying to help you by saying that you may set a breakpoint in malloc_error_break to find more about this object.
There may be several reasons for something like this to happen, the foremost reason that I have found is programmers trying to free something that is already in the auto-release pool.
So how to fix this up?
It’s fairly simple, You need to set a “symbolic breakpoint” on malloc_error_break .
Go to Run > Breakpoints > Add Symbolic Breakpoint. Then paste malloc_error_break into the window.
Here are some screenshots to describe the process:
After that activate the breakpoints and simply run. and the app’s execution will stop at the point where it sees you freeing the variable the second time.
參考:http://blog.csdn.net/devday/article/details/6460929
中級:使用 malloc_history 14003 0xb47fc50 在終端中查看
步驟1:設置參數
做如下設置:
Project -> Edit active executable ->Argument
添加如下四個參數
NSDebugEnabled
NSZombieEnabled
MallocStackLogging
MallocStackLoggingNoCompact
並都設置為YES。具體如下圖:
這個時候,如果有如下一段代碼:
//重復釋放一個變量
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSData* data = [NSData dataWithBytes:"asklaskdxjgr" length:12];
[data release];
[pool release];
再Debug窗口會有如下的提示
2003-03-18 13:01:38.644 autoreleasebug[3939] *** *** Selector 'release'
雖然也能大致判斷是哪種類型的變量重復釋放了,但信息還不夠多,當項目大,源碼比較多的時候,也不太方便定位,
在console窗口運行如下命令可以得到更多信息:shell malloc_history <pid> <address>
第二步:在終端(terminal中)輸入命令:malloc_history 3939 0xa4e10
就會出現更多的信息:
[dave@host193 Frameworks]$ malloc_history 3939 0xa4e10
Call [2] [arg=32]: thread_a0000dec |0x1000 | start | _start | main |
+[NSData dataWithBytes:length:] | NSAllocateObject | object_getIndexedIvars |
malloc_zone_calloc
這個時候就知道具體哪個函數出先問題了,從這里可以看到main里NSData出現問題了。
參考:iphone 內存管理的一些總結 很棒!
我的經驗:
1、在終端中輸入命令時,要保持xcode開啟,且程序正卡在端點處。
2、我用到命令是 malloc_history <pid> <address> ,返回的結果是:
ALLOC 0xb47fc50-0xb47fc6f [size=32]: thread_416c1a8 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -[UIApplication _reportAppLaunchFinished] | +[CATransaction flush] | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CA::Layer::layout_and_display_if_needed(CA::Transaction*) | CA::Layer::layout_if_needed(CA::Transaction*) | -[CALayer layoutSublayers] | -[NSObject performSelector:withObject:] | -[UIView(CALayerDelegate) layoutSublayersOfLayer:] | -[UILayoutContainerView layoutSubviews] | -[UINavigationController __viewWillLayoutSubviews] | -[UINavigationController _startDeferredTransitionIfNeeded:] | -[UINavigationController _startTransition:fromViewController:toViewController:] | -[UINavigationController _updateScrollViewFromViewController:toViewController:] | -[UINavigationController _layoutViewController:] | -[UIViewController loadViewIfRequired] | -[SQHomePageViewController viewDidLoad] | -[SQHomePageViewController requestRecommendList] | -[RecommendList requestRecommendList] | -[SQHomePageAction requestHomePage] | -[SQBaseAction requestUrl:] | -[ASIHTTPRequest startSynchronous] | -[NSRunLoop(NSRunLoop) runMode:beforeDate:] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSources0 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ | _cfstream_shared_signalEventSync | _signalEventSync | ReadStreamClientCallBack | -[ASIHTTPRequest handleNetworkEvent:] | -[ASIHTTPRequest handleStreamComplete] | -[ASIHTTPRequest requestFinished] | -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] | -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] | -[ASIHTTPRequest reportFinished] | __27-[SQBaseAction requestUrl:]_block_invoke | -[SQBaseAction onSuccess:] | -[SQBaseAction validResponse:] | -[SQBaseAction parserJsonWithString:] | -[NSDictionary initWithDictionary:] | -[NSDictionary initWithDictionary:copyItems:] | -[__NSPlaceholderDictionary initWithObjects:forKeys:count:] | +[__NSDictionaryI __new:::::] | __CFAllocateObject2 | class_createInstance | calloc | malloc_zone_calloc
問題定位在紅色函數中。
上面這段代碼應該是完整地描述了,程序執行的全部過程。包括每一個類和每一個方法。非常有意思。
實際出錯代碼:
//將json 格式的原始數據轉解析成數據字典 -(NSDictionary *)parserJsonWithString:(NSString *)str { NSString *strJson = [self removeEscapeCodeFromString:str]; SBJsonParser *sbJsonParser = [[[SBJsonParser alloc]init]autorelease]; NSDictionary *tempDictionary = [[NSDictionary alloc]initWithDictionary:[sbJsonParser objectWithString:strJson]]; return [tempDictionary autorelease]; //不必release或autorelease將自動釋放 }
參考: message sent to deallocated instance 講解的很詳細,值得參考
其它信息:
message sent to deallocated instance問題的解決方法(gdb和lldb) 當出現message sent to deallocated instance的時候,一般伴隨牛逼的BAD_ACCESS.是的,是某個對象release了兩次。可是那么多的疑似對象,到底是哪一個? 使用xcode環境變量(添加方法請自行google)MallocStackLoggingNoCompact,NSZombieEnabled,MallocStackLogging這三個,值都設置成YES.尋求更詳細的錯誤信息。 message sent to deallocated instance后會有一個內存地址,如:0×6497860,我們需要查看該地址的malloc history.查看方法,在原來的gdb下,使用”info malloc_history 0×6497860“即可顯示malloc記錄。但是新版的Xcode 不再支持,怎么辦呢?秀逗麻袋,我們還有terminal,使用終端的malloc_history命令,如”malloc_history 32009 0×6497860“即可顯示。其中的32009是該進程的pid,根據這個malloc記錄,可以大致定位出錯信息的代碼位置。 (插一句,gdb或者lldb進行debug的向導:http://lldb.llvm.org/lldb-gdb.html) 其實,如果代碼編寫足夠高效和有序的話,是不會出現這種煩人的問題的。還是代碼重構問題。代碼潔癖傷不起啊。 你好,請問pid具體是哪個進程的,通過活動監視器查看么?_是的,activity monitor