今天有用戶反饋,mac微信卡死在登錄界面,彩球一直轉(zhuǎn)。從現(xiàn)象來(lái)看,是主線程卡住了,難道是死循環(huán)了?進(jìn)一步地,開(kāi)啟調(diào)試符號(hào)("Build Settings"->"Strip Linked Product"置為NO),發(fā)現(xiàn)console里面狂刷主線程卡頓監(jiān)控日志,主要堆棧如下:
[I][][MMLagMonitor.mm, startMonitorWithCallback, 179]][INFO: Backtrace of Thread 775:
libsystem_kernel.dylib 0x7fff9a50ac22 __psynch_mutexwait + 10
Foundation 0x7fff866710e2 -[NSLock lock] + 145
WeChat 0x108e7bc68 -[MMCGINotifyCenter addDelegateInternal:sessionId:] + 59
WeChat 0x108e7bbef +[MMCGINotifyCenter addDelegate:sessionId:] + 83
WeChat 0x108a03630 -[MMCGI registerDelegate:] + 37
WeChat 0x108a034d8 -[MMCGI initWithItem:delegate:] + 140
WeChat 0x10889a16d -[MMCGIService RequestCGI:delegate:] + 302
WeChat 0x108e29126 -[AuthCGI QRCodeAuth:withPassword:] + 3859
WeChat 0x108e9c1d0 -[AccountService QRCodeLoginWithUserName:password:] + 58
WeChat 0x108dc5039 __34-[QRCodeLoginLogic setupQRCodeCGI]_block_invoke.38 + 330
WeChat 0x108b3f1e3 -[QRCodeLoginCG<…>
可以看到,NSLock一直在鎖等待,即死鎖了。 那么死鎖是怎么發(fā)生的呢?我們知道,NSLock是非遞歸鎖,當(dāng)同一線程重復(fù)獲取同一非遞歸鎖時(shí),就會(huì)發(fā)生死鎖。如下所示:
NSLock *m_lock;
[m_lock lock]; // 成功上鎖
do something....
[m_lock lock]; // 上面已經(jīng)上鎖,這里阻塞等待鎖釋放,不會(huì)再執(zhí)行下面,鎖永遠(yuǎn)得不到釋放,即死鎖
do something....
[m_lock unlock]; // 不會(huì)執(zhí)行到
do something....
[m_lock unlock];
于是,斷點(diǎn)跟蹤堆棧中相關(guān)問(wèn)題函數(shù)的調(diào)用關(guān)系,企圖找到如上所示的嵌套上鎖代碼,結(jié)果如下:


簡(jiǎn)化如下:
- (void)erase {
[m_lock lock];
dealloc();
[m_lock unlock];
}
- (void)dealloc {
erase();
}
另一方面,用NSRecursiveLock或者@synchronized替代NSLock,就可以成功登錄了。因?yàn)橥痪€程重復(fù)獲取同一遞歸鎖,不會(huì)發(fā)生死鎖。