1、ARC中,对于调用私有函数调用中,返回值是void 或者参数本身是基本类型的,如果使用了id,因为ARC中会对参数和返回值进行retain,所以都会产生objc_retain的crash。
delloc函数是异步的:当对对象调用release的时候,即使该对象的retaincount = 0,
该对象的delloc函数也不是同步调用的。
例子:UIWebViewWk的destory函数的原因。
2、通用的情景是:观察者使用的时候。
A->B->C
A做为B的观察者向下传递,B中的C会回调到A中方法。
传统的A的delloc方法中销毁B,B的delloc方法中销毁C。在OC中由于
对象release之后,delloc方法是异步调用的,A delloc之后,B的retainCount = 0,但是当B的delloc函数还没有
调用的时候,C发生回调,就会因为A的野指针crash。
这个时候就要实现B的destory方法来销毁C。
这个destory方法在A的delloc方法中进行调用。这样就保证了A delloc的时候C也delloc了。
3、docmentView上面加入手势,网页内容发生改变,如页内的视频跳转之后,手势发生crash.
4、panGesture手势没有调用touchMove,而初始化的代码放在了touchMove中,导致变量没有初始化,成为了野指针
5、属性对象没有retain,delloc的时候crash.
以下是更改的具体案例:
7、crash发生在C代码中,很难追踪到栈:bilsonzhou 3.0以前
0 libsystem_kernel.dylib 0x3432132c __pthread_kill (in libsystem_kernel.dylib) 8
1 libsystem_c.dylib 0x32e1829e abort (in libsystem_c.dylib) 94
2 libc abi.dylib 0x37589f6a abort_message (in libc abi.dylib) 46
3 libc abi.dylib 0x3758734c _ZL17default_terminatev (in libc abi.dylib) 24
4 libobjc.A.dylib 0x3692b36e _objc_terminate (in libobjc.A.dylib) 170
5 libc abi.dylib 0x375873c4 _ZL19safe_handler_callerPFvvE (in libc abi.dylib) 76
6 libc abi.dylib 0x37587450 operator delete(void*) (in libc abi.dylib) 0
7 libc abi.dylib 0x37588824 __cxa_current_exception_type (in libc abi.dylib) 0
8 libobjc.A.dylib 0x3692b2a8 objc_exception_rethrow (in libobjc.A.dylib) 12
9 CoreFoundation 0x35d6450c CFRunLoopRunSpecific (in CoreFoundation) 404
10 CoreFoundation 0x35d6436c CFRunLoopRunInMode (in CoreFoundation) 104
11 GraphicsServices 0x322e8438 GSEventRunModal (in GraphicsServices) 136
12 UIKit 0x3634ccd4 UIApplicationMain (in UIKit) 1080
13 MttHD 0x0000377e main (in MttHD) (main.m:15)
这个栈已经存在很长时间了,根本的Crash原因是对dictionary插入了nil对象。
为什么栈变得这么丑,找不到挂的地方?
因为这句代码写在了C代码中:
void appScoreDataManager_Init(); //初始化评分管理信息
// whetherScoredFlag
NSNumber *numberObject = [g_AppScoreDataManager objectForKey:WHEHTER_SCORED_FLAG];
if (nil == numberObject)
{
[g_AppScoreDataManager setObject:MTTWhetherScoredFlag forKey:WHEHTER_SCORED_FLAG];
}
// APP_USED_COUNT
numberObject = [g_AppScoreDataManager objectForKey:APP_USED_COUNT];
if (nil == numberObject)
{
[g_AppScoreDataManager setObject:MTTAppUsedCount forKey:APP_USED_COUNT];
}
由于if语句中的代码很难被执行,所以一直没有发现。这个地方如果MTTWhetherScoredFlag不是等于0的话,会产生一个警告,
我们将warning作为error之后,这个地方就会编译不通过,而恰恰这个地方MTTWhetherScoredFlag = 0。被当成了一个nil对象,
所以不会产生warning导致编译不通过。
8、释放一个autorelease对象:bilsonzhou 3.0以前
#0 0x3374ec98 in objc_msgSend ()
#1 0x3702bc36 in CFGetRetainCount ()
#2 0x34dc9c0e in CA::release_root_if_unused ()
#3 0x34dc9bba in x_hash_table_remove_if ()
#4 0x34da8f9c in CA::Transaction::commit ()
#5 0x34da2054 in CA::Transaction::observer_callback ()
#6 0x3706aa34 in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#7 0x3706c464 in __CFRunLoopDoObservers ()
#8 0x3706d75a in __CFRunLoopRun ()
#9 0x36ffdec2 in CFRunLoopRunSpecific ()
#10 0x36ffddca in CFRunLoopRunInMode ()
#11 0x3195641e in GSEventRunModal ()
#12 0x319564ca in GSEventRun ()
#13 0x30ff5d68 in -[UIApplication _run] ()
#14 0x30ff3806 in UIApplicationMain ()
#15 0x00003ede in main (argc=1, argv=0x2fdff880)
at /Users/bilsonzhou/Desktop/QQBrowserIPAD/src/MttHDBrowser_iPad/MttHD/MttHD/main.m:15
该bug在5.0以上系统很难重现,在4.3.3系统上面随机出现;
从这个栈看,没有我们的代码,也是鸟都看不出一个。
这是离线阅读引进的bug,由于时间较长,相关同事也离职,查找原因时花了较长时间。
通过4.3真机调试时发现了如下系统日志:
modifying layer that is being finalized - 0xd332410
基本上锁定为某个view进行了重复释放,通过对离线阅读中释放的对象一一排查,
最后锁定为:
m_btnDel = [UIButton buttonWithType:UIButtonTypeCustom];
在delloc中
[m_btnDel release];
这种crash虽然原因很简单,但是由于随机性和crash栈的信息有限,查找的难度很大。
9、内存被写坏导致随机crash,crash堆栈如下 3.0以前
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000028
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 WebKit 0x393cfe62 -[WebView(WebPrivate) _loadBackForwardListFromOtherView:] + 130
1 MttHD 0x0009e364 -[UIWebViewWK loadUrlFromOtherWK:] (UIWebViewWK.mm:4741)
2 MttHD 0x0001a432 -[UIMttBrowserView preloadUrls:] (UIMttBrowserView.m:6341)
3 Foundation 0x33408652 __NSFireDelayedPerform + 446
4 CoreFoundation 0x32ace854 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 12
5 CoreFoundation 0x32ace4fe __CFRunLoopDoTimer + 270
6 CoreFoundation 0x32acd172 __CFRunLoopRun + 1226
7 CoreFoundation 0x32a40238 CFRunLoopRunSpecific + 352
8 CoreFoundation 0x32a400c4 CFRunLoopRunInMode + 100
9 GraphicsServices 0x365fb336 GSEventRunModal + 70
10 UIKit 0x3495c2b4 UIApplicationMain + 1116
11 MttHD 0x00003982 main (main.m:15)
12 MttHD 0x00003934 0x1000 + 10548
从上面crash线程的堆栈很难找到问题,再往下下面其它线程的堆栈;
Thread 16 name: Dispatch queue: com.apple.root.low-priority
Thread 16:
0 libsystem_kernel.dylib 0x3ae66e30 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3ae66fd0 mach_msg + 48
2 CoreFoundation 0x32ace2b6 __CFRunLoopServiceMachPort + 126
3 CoreFoundation 0x32acd02c __CFRunLoopRun + 900
4 CoreFoundation 0x32a40238 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x32a400c4 CFRunLoopRunInMode + 100
6 CFNetwork 0x327a1612 CFURLConnectionSendSynchronousRequest + 330
7 Foundation 0x334353da +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242
8 MttHD 0x0019d76c __30-[MttSubscribeImage pullImage]_block_invoke_0 (MttSubscribeImage.m:310)
9 MttHD 0x0019eaca __41-[MttSubscribeTaskQueue dispatch:forKey:]_block_invoke_075 (MttSubscribeTaskQueue.m:161)
10 libdispatch.dylib 0x3ad9d790 _dispatch_call_block_and_release + 8
11 libdispatch.dylib 0x3ada1652 _dispatch_root_queue_drain + 274
12 libdispatch.dylib 0x3ada17d4 _dispatch_worker_thread2 + 88
13 libsystem_c.dylib 0x3adc57ee _pthread_wqthread + 358
14 libsystem_c.dylib 0x3adc5680 start_wqthread + 4
发现一个可疑的线程,该线程的堆栈正好跑完并等待中,恰好是有程序本身的代码,通过review堆栈中的代码发现,response变量没有初始化。
NSHTTPURLResponse *response ;
self.data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: nil];
为什么没有初始化会导致crash呢?因为sendSynchronousRequest 的 returningResponse变量是out型变量,则函数会把结果写入returningResponse变量中,
当response没有初始化的时候系统默认会给它一个随机内存,sendSynchronousRequest 函数将内容写入这块随机内存程序以后的运行很可能会导致随机crash。
10、对象实例调用自身函数release自身实例导致crash 3.0以前
在MttVideoView类对象实例的dismissVideoView函数同步调用了closeVideoView将自身实例从UI树移除并release自身,从而导致随机crash,crash的堆栈
如下:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0xc0000008
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x3358bc98 objc_msgSend + 16
1 CoreFoundation 0x36e33cd6 CFRetain + 62
2 CoreFoundation 0x36e3a176 +[__NSArrayI __new::] + 54
3 CoreFoundation 0x36e38a6e -[__NSPlaceholderArray initWithObjects:count:] + 122
4 QuartzCore 0x34c01db6 -[CALayerArray copyWithZone:] + 42
5 CoreFoundation 0x36e39b4a -[NSObject(NSObject) copy] + 10
6 UIKit 0x30e2bd7c -[UIView dealloc] + 52
7 MttHD 0x001e83e8 -[MttVideoView dealloc] (MttVideoView.m:378)
8 CoreFoundation 0x36e34c3c -[NSObject(NSObject) release] + 24
9 CoreFoundation 0x36e3519a CFRelease + 62
10 CoreFoundation 0x36e3aba2 -[__NSArrayM dealloc] + 86
11 CoreFoundation 0x36e34c3c -[NSObject(NSObject) release] + 24
12 CoreFoundation 0x36e3519a CFRelease + 62
13 CoreFoundation 0x36e37eb4 _CFAutoreleasePoolPop + 140
14 Foundation 0x33725bae NSPopAutoreleasePool + 2
15 Foundation 0x337aa73c __NSFireDelayedPerform + 472
16 CoreFoundation 0x36ea7a40 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 8
17 CoreFoundation 0x36ea9ec4 __CFRunLoopDoTimer + 844
18 CoreFoundation 0x36eaa83e __CFRunLoopRun + 1082
19 CoreFoundation 0x36e3aebc CFRunLoopRunSpecific + 224
20 CoreFoundation 0x36e3adc4 CFRunLoopRunInMode + 52
21 GraphicsServices 0x31793418 GSEventRunModal + 108
22 GraphicsServices 0x317934c4 GSEventRun + 56
23 UIKit 0x30e32d62 -[UIApplication _run] + 398
24 UIKit 0x30e30800 UIApplicationMain + 664
25 MttHD 0x00003800 main (main.m:15)
26 MttHD 0x000037b0 0x1000 + 10160
这个是手动点击删除小窗口按钮退出小窗口的,结合代码分析,删除这个实例的堆栈必须有函数closeVideoView ,但是从crash的堆栈上看,没有发现函数closeVideoView的堆栈,
觉得很诡异,不符合堆栈逻辑。为什么会出现上面的堆栈呢?是因为该实例的函数调用栈还没有完成退出就调用自身的dealloc函数将自己删除掉了,
导致栈上的地址出现随机错误。
解决总结:要删除实例自身,应该要用异步延时删除,不能同步删除。
11、加入手势的对象发生了变化 bilsonzhou 3.0以前
Thread 2 Crashed:
0 libsystem_kernel.dylib 0x33db3a1c __pthread_kill + 8
1 libsystem_c.dylib 0x34aa73b4 pthread_kill + 52
2 libsystem_c.dylib 0x34a9fb78 __abort + 80
3 libsystem_c.dylib 0x34a9fc18 abort + 104
4 libstdc++.6.dylib 0x35470a64 __gnu_cxx::__verbose_terminate_handler() + 376
5 libobjc.A.dylib 0x32ce706c _objc_terminate + 104
6 libstdc++.6.dylib 0x3546ee36 __cxxabiv1::__terminate(void (*)()) + 46
7 libstdc++.6.dylib 0x3546ee8a std::terminate() + 10
8 libstdc++.6.dylib 0x3546ef5a __cxa_throw + 78
9 libobjc.A.dylib 0x32ce5c84 objc_exception_throw + 64
10 CoreFoundation 0x36593062 -[__NSArrayM objectAtIndex:] + 178
11 CoreFoundation 0x365ba130 -[NSMutableArray removeObject:range:identical:] + 284
12 CoreFoundation 0x365b9ffa -[NSMutableArray removeObject:] + 46
13 UIKit 0x305e31fe -[UIView(UIViewGestures) removeGestureRecognizer:] + 54
14 UIKit 0x305e3004 -[UIWebSelectionAssistant setGestureRecognizers] + 48
15 UIKit 0x305e4408 -[UIWebSelectionAssistant setEnabled:] + 48
16 UIKit 0x30664c70 -[UIWebDocumentView loadRequest:] + 168
17 CoreFoundation 0x3662b79c __invoking___ + 60
18 CoreFoundation 0x365a3436 -[NSInvocation invoke] + 102
19 WebCore 0x35c29c36 _ZL11SendMessageP12NSInvocation + 10
20 WebCore 0x35c29c0e _ZL15HandleAPISourcePv + 66
21 CoreFoundation 0x365ffa72 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 6
22 CoreFoundation 0x36601758 __CFRunLoopDoSources0 + 376
23 CoreFoundation 0x366024e4 __CFRunLoopRun + 224
24 CoreFoundation 0x36592ebc CFRunLoopRunSpecific + 224
25 CoreFoundation 0x36592dc4 CFRunLoopRunInMode + 52
26 WebCore 0x35c2827e _ZL12RunWebThreadPv + 382
27 libsystem_c.dylib 0x34aa730a _pthread_start + 242
28 libsystem_c.dylib 0x34aa8bb4 thread_start + 0
这是个随机的bug,栈里面也没有我们的代码。幸好4.3系统在腾讯视频发生页内跳转之后该crash高概率出现了。
最后发现原因是;网页的双指单击手势加到了documentView上面,发生页内跳转之后documentView的内容发生了变化。在网页释放的时候就挂了。
修改方法是把手势加到了网页的scroll上面。
12、手势crash. bilsonzhou 3.0以前 3.1修复
0 libobjc.A.dylib 0x3b41c692 0x3b419000 13970
1 MttHD 0x000fce4c -[GestureDetectWindow handleOneFingerPan:] (in MttHD) (GestureDetectWindow.m:237)
2 UIKit 0x354a6d88 0x35386000 1183112
3 UIKit 0x3546e3f4 0x35386000 951284
4 UIKit 0x3565ba38 0x35386000 2972216
5 UIKit 0x3539282e 0x35386000 51246
6 UIKit 0x35391292 0x35386000 45714
7 UIKit 0x3539c1e6 0x35386000 90598
8 UIKit 0x3539bdb2 0x35386000 89522
9 UIKit 0x35389800 0x35386000 14336
10 UIKit 0x3538911a 0x35386000 12570
11 GraphicsServices 0x370925a2 0x3708c000 26018
12 GraphicsServices 0x370921d2 0x3708c000 25042
13 CoreFoundation 0x33556172 0x334bf000 618866
14 CoreFoundation 0x33556116 0x334bf000 618774
15 CoreFoundation 0x33554f98 0x334bf000 614296
16 CoreFoundation 0x334c7ebc 0x334bf000 36540
17 CoreFoundation 0x334c7d48 0x334bf000 36168
18 GraphicsServices 0x370912ea 0x3708c000 21226
19 UIKit 0x353dd300 0x35386000 357120
20 MttHD 0x0000331e main (in MttHD) (main.m:15)
该crash在以前版本一直有上报,3.0更改手势机制之后上报量突然增大。
在3.0灰度版本的时候就有上报,但是上报的栈指向的是MttBrowserView成了野指针。如果
browserview都成了野指针那整个浏览器都野了,因此灰度之后排查了browserView中成员变量。对照3.0以前相关crash附近手势的代码进行了更改。
结果发出去之后还是有大量的上报。后来通过打印大量日志后发现,panGesture手势的三个过程:
touch begin,move,end。不是每次调用都会进入move。而我们的变量初始化都放在了move当中,move没有调用导致变量没有初始化野指针crash.
这个地方日志上报的栈中的行数并不是确定的。
13、NSRange Exception crash bilsonzhou 3.2引入
0 CoreFoundation 0x36dde29e __exceptionPreprocess + 158
1 libobjc.A.dylib 0x3738697a objc_exception_throw + 26
2 CoreFoundation 0x36dde1c0 +[NSException raise:format:] + 100
3 Foundation 0x32ab175e -[NSData(NSData) subdataWithRange:] + 174
4 MttHD 0x002300bc -[MTTCommandTunnel _send] (MTTCommandTunnel.m:194)
5 MttHD 0x0022f950 -[MTTCommandTunnel streamHasSpaceAvailable:] (MTTCommandTunnel.m:126)
6 MttHD 0x0023025e -[MTTCommandTunnel stream:handleEvent:] (MTTCommandTunnel.m:239)
7 CoreFoundation 0x36d7b7ca _signalEventSync + 70
8 CoreFoundation 0x36d8161e _cfstream_solo_signalEventSync + 70
9 CoreFoundation 0x36d7b502 _CFStreamSignalEvent + 322
10 CFNetwork 0x32446862 CoreWriteStreamCFStreamSupport::coreStreamWriteEvent(__CoreWriteStream*, unsigned long) + 94
11 CFNetwork 0x32446218 CoreWriteStreamClient::coreStreamEventsAvailable(unsigned long) + 32
12 CFNetwork 0x324474c8 CoreStreamBase::_callClientNow() + 40
13 CFNetwork 0x3244725c CoreStreamBase::_streamSetEventAndScheduleDelivery(unsigned long, unsigned char) + 84
14 CFNetwork 0x32447662 CoreStreamBase::_streamInterface_SignalEvent(unsigned long, CFStreamError const*) + 30
15 CFNetwork 0x323b5c76 SocketStream::socketCallback(__CFSocket*, unsigned long, __CFData const*, void const*) + 130
16 CFNetwork 0x323b5bd6 SocketStream::_SocketCallBack_stream(__CFSocket*, unsigned long, __CFData const*, void const*, void*) + 70
17 CoreFoundation 0x36db5f18 __CFSocketPerformV0 + 792
18 CoreFoundation 0x36db367e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 10
19 CoreFoundation 0x36db2f7a __CFRunLoopDoSources0 + 358
20 CoreFoundation 0x36db1cb2 __CFRunLoopRun + 642
21 CoreFoundation 0x36d24eb8 CFRunLoopRunSpecific + 352
22 CoreFoundation 0x36d839b6 CFRunLoopRun + 94
23 MttHD 0x0022f7b6 -[MTTCommandTunnel tunnelThreadMain:] (MTTCommandTunnel.m:113)
24 Foundation 0x32b28678 __NSThread__main__ + 968
25 libsystem_c.dylib 0x337da30c _pthread_start + 304
26 libsystem_c.dylib 0x337da1d4 thread_start + 4
挂的原因是NSRange越界了。
NSInteger length = [self.outputStream write:self.sendBuffer.bytes maxLength:self.sendBuffer.length];
self.sendBuffer = [self.sendBuffer subdataWithRange:NSMakeRange(length, self.sendBuffer.length - length)].mutableCopy;
前一句代码的写动作出错了,返回-1,由于NSRange为无符号型的,最后就发生溢出,成为一个超大整数发生越界。
对于会抛出异常的代码,尤其是数组,字符串类操作比较多的代码,最后try catch 一下。再通过和MTTEXCEPTIONLOG()在catch中输出exception信息。
我添加了两个新的log宏定义MTTERRORLOG()和MTTEXCEPTIONLOG(),这两个宏在调试的时候会很显眼的输出错误信息,并且会将程序主动crash。
便于发现问题。发布版本不会收到影响。
14、initStringWithCString crash bilsonzhou 3.2引入
0 libsystem_c.dylib 0x31e43884 strlen + 12
1 CoreFoundation 0x329e4fa8 CFStringCreateWithCString + 12
2 MttHD 0x0022426e -[ShareView addFavoriteRequest:withPageURL:shareEntrance:] (ShareView.m:349)
3 MttHD 0x00223ac4 -[ShareView addFavoritePage] (ShareView.m:239)
4 MttHD 0x00223a64 -[ShareView canAddFavoritePage] (ShareView.m:231)
5 MttHD 0x002234e8 -[ShareView handleTouchUp:] (ShareView.m:118)
6 CoreFoundation 0x329e83f6 -[NSObject performSelector:withObject:withObject:] + 46
7 UIKit 0x34fb0e00 -[UIApplication sendAction:to:from:forEvent:] + 56
8 UIKit 0x34fb0dbc -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 24
9 UIKit 0x34fb0d9a -[UIControl sendAction:to:forEvent:] + 38
10 UIKit 0x34fb0b0a -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 486
11 UIKit 0x34fb1442 -[UIControl touchesEnded:withEvent:] + 470
12 UIKit 0x34faf924 -[UIWindow _sendTouchesForEvent:] + 312
13 UIKit 0x34faf312 -[UIWindow sendEvent:] + 374
14 DisplayRecorder.dylib 0x00bb5998 0xba9000 + 51608
15 UIKit 0x34f9568e -[UIApplication sendEvent:] + 350
16 UIKit 0x34f94f34 _UIApplicationHandleEvent + 5820
17 GraphicsServices 0x32b32224 PurpleEventCallback + 876
18 CoreFoundation 0x32a6251c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
19 CoreFoundation 0x32a624be __CFRunLoopDoSource1 + 134
20 CoreFoundation 0x32a6130c __CFRunLoopRun + 1364
21 CoreFoundation 0x329e449e CFRunLoopRunSpecific + 294
22 CoreFoundation 0x329e4366 CFRunLoopRunInMode + 98
23 GraphicsServices 0x32b31432 GSEventRunModal + 130
24 UIKit 0x34fc3cce UIApplicationMain + 1074
25 MttHD 0x00003700 main (main.m:15)
26 MttHD 0x000036b0 0x1000 + 9904
通常NSString的函数如果传入nil对象是会抛出异常的,但是initStringWithCString这个方法传入nil对象是badexec错误。再调用的时候要记得判断。
15 数据库的单列进行多线程访问 crash bilsonzhou 3.0以前引入
0 libsqlite3.dylib 0x3c321524 0x390a3524 (in libsqlite3.dylib) 5212
1 libsqlite3.dylib 0x3c31faae 0x390a1aae (in libsqlite3.dylib) 326
2 libsqlite3.dylib 0x3c317288 0x39099288 (in libsqlite3.dylib) 6288
3 libsqlite3.dylib 0x3c3060d0 0x390880d0 (in libsqlite3.dylib) 5776
4 libsqlite3.dylib 0x3c304980 0x39086980 (in libsqlite3.dylib) 244
5 libsqlite3.dylib 0x3c304144 0x39086144 (in libsqlite3.dylib) 300
6 libsqlite3.dylib 0x3c303c0e 0x39085c0e (in libsqlite3.dylib) 514
7 libsqlite3.dylib 0x3c30396e 0x3908596e (in libsqlite3.dylib) 262
8 libsqlite3.dylib 0x3c33a956 sqlite3_prepare_v2 (in libsqlite3.dylib) 30
9 MttHD 0x0020de14 -[FMDatabase executeQuery:withArgumentsInArray:orVAList:] (in MttHD) (FMDatabase.m:327)
10 MttHD 0x0020dfd8 -[FMDatabase executeQuery:] (in MttHD) (FMDatabase.m:432)
11 MttHD 0x0003fc0a -[MttHistoryManager mostVisitRecordByID:] (in MttHD) (MttHistoryManager.m:715)
12 MttHD 0x000410ce -[MttHistoryManager mostVisitStartPageRecord] (in MttHD) (MttHistoryManager.m:1141)
13 MttHD 0x001968f6 -[QuicklinkViewNew getUnLockItemCount] (in MttHD) (QuicklinkViewNew.m:1483)
14 MttHD 0x0012a490 -[MttHDStatInfo protocol] (in MttHD) (MttHDStatInfo.m:179)
15 MttHD 0x00114898 [MttSTStat(Adapter) mtthdInstance] (in MttHD) (MttSTStat Adapter.m:39)
16 MttHD 0x00122bec __52-[MttStatService statWithCompleteBlock:failedBlock:]_block_invoke_06 (in MttHD) (MttStatService.m:38)
17 libdispatch.dylib 0x3c52111e _dispatch_call_block_and_release (in libdispatch.dylib) 10
18 libdispatch.dylib 0x3c524ece _dispatch_queue_drain$VARIANT$mp (in libdispatch.dylib) 142
19 libdispatch.dylib 0x3c524dc0 _dispatch_queue_invoke$VARIANT$mp (in libdispatch.dylib) 40
20 libdispatch.dylib 0x3c52591c _dispatch_root_queue_drain (in libdispatch.dylib) 184
21 libdispatch.dylib 0x3c525ac0 _dispatch_worker_thread2 (in libdispatch.dylib) 84
22 libsystem_c.dylib 0x3c555a10 _pthread_wqthread (in libsystem_c.dylib) 360
多个线程都同时对数据库进行访问,造成冲突之后crash。
很多使用单例的地方,如果不做好同步,都有造成线程冲突crash的风险。
解决方法:由于子线程访问数据库的地方不多,将访问数据库都同步到了主线程。
16 进度条绘制和内核的图片绘制冲突 bilsonzhou 3.0以前引入
Thread 0 Crashed:
0 CoreGraphics 0x3732b1b0 DYLD-STUB$$ceilf + 0
1 CoreGraphics 0x3723cc86 CGRectIntegral + 86
2 CoreGraphics 0x3724bb82 CGImageBlockCreate + 106
3 ImageIO 0x3349fc70 copyImageBlockSetPNG + 1820
4 ImageIO 0x3349f35e ImageProviderCopyImageBlockSetCallback + 202
5 CoreGraphics 0x3724baf6 CGImageProviderCopyImageBlockSetWithOptions + 226
6 CoreGraphics 0x3724ba00 CGImageProviderCopyImageBlockSet + 32
7 CoreGraphics 0x3724b72e img_blocks_create + 182
8 CoreGraphics 0x37247140 img_data_lock + 1656
9 CoreGraphics 0x372463b8 CGSImageDataLock + 104
10 libRIP.A.dylib 0x3477f63c ripc_AcquireImage + 2676
11 libRIP.A.dylib 0x3477cc52 ripc_DrawImage + 462
12 CoreGraphics 0x37246284 CGContextDelegateDrawImage + 44
13 CoreGraphics 0x37246142 CGContextDrawImage + 250
14 MttHD 0x000256f4 -[AJProgressLayer drawInContext:] (UIMttBrowserAddressField.m:89)
15 QuartzCore 0x34cbdd24 _ZL16backing_callbackP9CGContextPv + 32
16 QuartzCore 0x34cbd776 CABackingStoreUpdate + 1226
17 QuartzCore 0x34cbd178 -[CALayer _display] + 724
18 QuartzCore 0x34cbce86 -[CALayer display] + 134
19 QuartzCore 0x34cb1706 CALayerDisplayIfNeeded + 178
20 QuartzCore 0x34cb11c6 CA::Context::commit_transaction(CA::Transaction*) + 214
21 QuartzCore 0x34cb0fd0 CA::Transaction::commit() + 184
22 QuartzCore 0x34caa04e CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 50
23 CoreFoundation 0x36f72a2e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 10
24 CoreFoundation 0x36f7445e __CFRunLoopDoObservers + 406
25 CoreFoundation 0x36f75754 __CFRunLoopRun + 848
26 CoreFoundation 0x36f05ebc CFRunLoopRunSpecific + 224
27 CoreFoundation 0x36f05dc4 CFRunLoopRunInMode + 52
28 GraphicsServices 0x3185e418 GSEventRunModal + 108
29 GraphicsServices 0x3185e4c4 GSEventRun + 56
30 UIKit 0x30efdd62 -[UIApplication _run] + 398
31 UIKit 0x30efb800 UIApplicationMain + 664
32 MttHD 0x00003578 main (main.m:15)
33 MttHD 0x00003528 0x1000 + 9512
mttf偶尔会有该栈的上报,老俞在访问百度贴吧很多图片的时候产生了该crash,在内核线程中也发现了drawInContext函数。
猜测CGContextDrawImage绘制图片和内核绘制图片产生了线程冲突。通过img的drawInRect函数重写了进度条的绘制进行了规避。
17 UIImageWriteToSavedPhotosAlbum 会产生异常 3.2以前引入
0 CoreFoundation 0x341ae8be __exceptionPreprocess (in CoreFoundation) 162
1 libobjc.A.dylib 0x358ca1e4 objc_exception_throw (in libobjc.A.dylib) 32
2 CoreData 0x33b7064a -[NSPersistentStoreCoordinator setMetadata:forPersistentStore:] (in CoreData) 410
3 PhotoLibraryServices 0x328efbb8 [PLManagedObjectContext(Private) recordVersion:forStore:] (in PhotoLibraryServices) 392
4 PhotoLibraryServices 0x328f0022 [PLManagedObjectContext(Private) configurePersistentStoreCoordinator:] (in PhotoLibraryServices) 1122
5 PhotoLibraryServices 0x328f069a __69 [PLManagedObjectContext(Protected) sharedPersistentStoreCoordinator]_block_invoke_0346 (in PhotoLibraryServices) 178
6 libdispatch.dylib 0x374907ea _dispatch_barrier_sync_f_invoke (in libdispatch.dylib) 22
7 libdispatch.dylib 0x3749065a dispatch_barrier_sync_f$VARIANT$up (in libdispatch.dylib) 62
8 libdispatch.dylib 0x3749028e dispatch_sync_f$VARIANT$up (in libdispatch.dylib) 18
9 libdispatch.dylib 0x37490910 dispatch_sync$VARIANT$up (in libdispatch.dylib) 32
10 PhotoLibraryServices 0x328f059a [PLManagedObjectContext(Protected) sharedPersistentStoreCoordinator] (in PhotoLibraryServices) 154
11 PhotoLibraryServices 0x328eed94 -[PLManagedObjectContext initWithConcurrencyType:useSharedPersistentStoreCoordinator:] (in PhotoLibraryServices) 120
12 PhotoLibraryServices 0x328eec72 [PLManagedObjectContext contextForPhotoLibrary:] (in PhotoLibraryServices) 114
13 PhotoLibraryServices 0x328ee894 -[PLPhotoLibrary(Protected) loadDatabase] (in PhotoLibraryServices) 236
14 PhotoLibraryServices 0x328b7184 -[PLPhotoLibrary initWithPath:canTriggerDatabaseUpdate:] (in PhotoLibraryServices) 304
15 PhotoLibraryServices 0x328fe1a4 __42 [PLSharedPhotoLibrary sharedPhotoLibrary]_block_invoke_0 (in PhotoLibraryServices) 60
16 libdispatch.dylib 0x37492576 dispatch_once_f$VARIANT$up (in libdispatch.dylib) 42
17 PhotoLibraryServices 0x328fe162 [PLSharedPhotoLibrary sharedPhotoLibrary] (in PhotoLibraryServices) 82
18 PhotoLibraryServices 0x328bf06e __withSavedPhotosAlbumUUID_block_invoke_0 (in PhotoLibraryServices) 50
19 libdispatch.dylib 0x37492576 dispatch_once_f$VARIANT$up (in libdispatch.dylib) 42
20 PhotoLibraryServices 0x328be436 withSavedPhotosAlbumUUID (in PhotoLibraryServices) 186
21 PhotoLibraryServices 0x328be378 PLSaveImageToCameraRoll (in PhotoLibraryServices) 76
22 UIKit 0x354831d4 UIImageWriteToSavedPhotosAlbum (in UIKit) 76
23 MttHD 0x001b0eb0 -[MttImageArticleMainView tapButton:] (in MttHD) (MttImageArticleMainVIew.m:983)
24 CoreFoundation 0x34108434 -[NSObject performSelector:withObject:withObject:] (in CoreFoundation) 52
25 UIKit 0x352369ea -[UIApplication sendAction:to:from:forEvent:] (in UIKit) 62
26 UIKit 0x352369a6 -[UIApplication sendAction:toTarget:fromSender:forEvent:] (in UIKit) 30
27 UIKit 0x35236984 -[UIControl sendAction:to:forEvent:] (in UIKit) 44
28 UIKit 0x352366f4 -[UIControl(Internal) _sendActionsForEvents:withEvent:] (in UIKit) 492
29 UIKit 0x3523702c -[UIControl touchesEnded:withEvent:] (in UIKit) 476
30 UIKit 0x3523550e -[UIWindow _sendTouchesForEvent:] (in UIKit) 318
31 UIKit 0x35234f00 -[UIWindow sendEvent:] (in UIKit) 380
32 UIKit 0x3521b4ec -[UIApplication sendEvent:] (in UIKit) 356
33 UIKit 0x3521ad2c _UIApplicationHandleEvent (in UIKit) 5808
34 GraphicsServices 0x35d45df2 PurpleEventCallback (in GraphicsServices) 882
35 CoreFoundation 0x34182552 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ (in CoreFoundation) 38
36 CoreFoundation 0x341824f4 __CFRunLoopDoSource1 (in CoreFoundation) 140
37 CoreFoundation 0x34181342 __CFRunLoopRun (in CoreFoundation) 1370
38 CoreFoundation 0x341044dc CFRunLoopRunSpecific (in CoreFoundation) 300
39 CoreFoundation 0x341043a4 CFRunLoopRunInMode (in CoreFoundation) 104
40 GraphicsServices 0x35d44fcc GSEventRunModal (in GraphicsServices) 156
41 UIKit 0x35249742 UIApplicationMain (in UIKit) 1090
42 MttHD 0x0000377e main (in MttHD) (main.m:15)
43 MttHD 0x00003730 start (in MttHD) 40
UIImageWriteToSavedPhotosAlbum这个函数会抛出异常,在网页图片那块保存到本地我就修改过一次。后来的同学估计不知道,又
没有捕获。看来分析还是很有必要的。
18、performSelector 操作会对对象本身retain一下。ranger bilsonzhou
由于异步操作会对对象本身进行一次retain,如果将异步操作放在delloc中cancel。会造成对象的延迟释放,如果这时候对观察者产生
回调的话就会有crash发生。
例如:
A->B->C
A做为B的观察者向下传递,B中的C会回调到A中方法。
传统的A的delloc方法中销毁B,B的delloc方法中销毁C。由于异步操作造成B延迟释放,
A delloc之后,B没有立即放生释放,这时候B产生回调或者C发生回调,就会因为A的野指针crash。
搜索框的crash的根本原因也是这个,下面是crash栈
Thread 0:
0 libobjc.A.dylib 0x33a54c98 objc_msgSend + 16
1 MttHD 0x000547e4 -[UIToolbarSearchInputPopMenuController onGetAssociationOfInput:data:] (UIToolbarSearchInputPopMenuController.m:574)
2 MttHD 0x00203380 __block_global_0 (MttGetAssociationalService.m:58)
3 libdispatch.dylib 0x338669c2 _dispatch_barrier_sync_f_slow_invoke + 62
4 libdispatch.dylib 0x338670e6 _dispatch_main_queue_callback_4CF$VARIANT$mp + 282
5 CoreFoundation 0x37373934 __CFRunLoopRun + 1328
6 CoreFoundation 0x37303ebc CFRunLoopRunSpecific + 224
7 CoreFoundation 0x37303dc4 CFRunLoopRunInMode + 52
8 GraphicsServices 0x31c5c418 GSEventRunModal + 108
9 GraphicsServices 0x31c5c4c4 GSEventRun + 56
10 UIKit 0x312fbd62 -[UIApplication _run] + 398
11 UIKit 0x312f9800 UIApplicationMain + 664
12 MttHD 0x00003740 main (main.m:15)
13 MttHD 0x000036f0 0x1000 + 9968
- (void)onGetAssociationOfInput:(NSString *)keyWord data:(NSArray *)result
{
NSString* lastSearchKeyWord = keyWord;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(loadSearchRecord) object:nil];
[[MttHDStatInfo theSpecial] statUserBehavior:MttHDUserBehavior_Receive_Associational];
NSString *searchString = self.searchString;
这个地方是搜索热词的回调代码,这里面的self在输入弹出框消失的时候会先进行一次释放,
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(loadSearchRecord) object:nil];
这句代码会将异步对自身的retain再释放一次。如果网络情况差,热词回调慢于弹出框释放,上面
的代码的实际执行就会如下:
NSString* lastSearchKeyWord = keyWord;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(loadSearchRecord) object:nil];
[[MttHDStatInfo theSpecial] statUserBehavior:MttHDUserBehavior_Receive_Associational];
[self release];
[self delloc];
//这时候self已经野了,这句话以执行就会野指针挂掉
NSString *searchString = self.searchString;
这个crash的随机性很高,通常情况时热词先回来,弹出框再消失就不会发生,只有在网络回调慢的时候才会发生。
针对这种情况,需要对有异步操作的函数写一个destroy函数来cancel异步操作,在观察者发生释放的时候调用destroy函数。以达到同步释放
后续这块会对异步操作进行梳理。
19、代理对象被释放,delegate没有设置Nil,delegate回调野指针导致block发生crash. 3.2引入 bilsonzhou
0 libobjc.A.dylib 0x317dff78 objc_msgSend (in libobjc.A.dylib) 16
1 libdispatch.dylib 0x3491fc58 _dispatch_call_block_and_release (in libdispatch.dylib) 12
2 libdispatch.dylib 0x34921ee6 _dispatch_main_queue_callback_4CF$VARIANT$mp (in libdispatch.dylib) 194
3 CoreFoundation 0x377432ac __CFRunLoopRun (in CoreFoundation) 1268
4 CoreFoundation 0x376c64a4 CFRunLoopRunSpecific (in CoreFoundation) 300
5 CoreFoundation 0x376c636c CFRunLoopRunInMode (in CoreFoundation) 104
6 GraphicsServices 0x378bf438 GSEventRunModal (in GraphicsServices) 136
7 UIKit 0x308d2cd4 UIApplicationMain (in UIKit) 1080
8 MttHD 0x00003ace main (in MttHD) (main.m:15)
订阅第二屏subscribItem被释放了,但是wup回调的delegate没有被设置空。
在读取数据的轮询函数中,将
if(imageData == nil)
{
return;
}
注释掉了。
之后下面的:
[_subscribeWupManager release];
_sbuscribeWupManager = nil;
代码被调用,在弱网络环境下,wup的回调如果还没有回来,这个时候由于wup里面的block会retain _subscribeWupManager自身。
当 subscribItem delloc的时候调用 _subscribeWupManager.delegate = nil;这时候的_subscribeWupManager已经是一个指向
nil的指针。而真正的_subscribeWupManager此时并没有释放,但是它的delegate已经释放,这时候发生回调就发生Crash了.