功能開發到一定程度,就進入優化階段.
今天來嘗試一下內存泄露的調優
先理清楚幾個基本概念:
1. 什么是內存泄露
就是你new了一個東西,但是沒有及時的釋放掉. 因為內存的東西是只增不減的,如果你不及時釋放掉,就會這些無用的數據一直占用內存。最后撐爆掉
2.怎么解決內存泄露
釋放掉就好了。專業說起來有一大堆,本質就是release
備注:目前iOS已有ARC模式,而且目前大部分APP都會遵從這種模式,所以大部分場景是不需要考慮內存泄露這些問題的
(但是用不用和需要不需要知道是2個概念,本著學習的原則,我們還是要know something...)
3. iOS怎么查看內存泄露
3.1 自己查代碼。每次alloc 的時候,銘記release
3.2 使用instrument查看,截圖如下:
Xcode: Product->Profile->Leak
http://www.cocoachina.com/industry/20140114/7696.html
常見技巧:
HandicapPickerAccessoryView* accessoryView = [HandicapPickerAccessoryView
viewWithNoHandicapClickedHandler:^(id sender) {
//
}
andConfirmClickedHandler:^(id sender) {
[weakSelf handicapUpdated:self.handicap];
}];
這里self.handicap就可能引發內存泄露,解決方案是:
__weak typeof(self) weakSelf = self;
HandicapPickerAccessoryView* accessoryView = [HandicapPickerAccessoryView
viewWithNoHandicapClickedHandler:^(id sender) {
//
}
andConfirmClickedHandler:^(id sender) {
[weakSelf handicapUpdated: weakSelf.handicap];
}];
備注點:加個weak的self就可以,不過留心點,之前遇到過同事代碼寫太快了,寫成如下這樣. (忘記了weak. ---這就屬于心里知道,但是寫錯了,查代碼也不是那么容易一看出來...)
typeof(self) weakSelf = self;
|
4. 特殊情況:Core Foundation object
目前已經使用了ARC. 但是還是出現了內存泄露的點
instrument查看下來是路徑繪制的地方出現了問題
"CG::Path::copy_as_sequence_on_write()+0x63"
"DYLD-STUB$$malloc"
查下來是之前做了一個數字icon . 類似購物車,右上角顯示已經買個幾個物品。
有一段代碼是這樣子的
這個是基于內容(比如1,2,...n)繪制badge的形狀(CGMutablePathRef).
使用其的地方如下:
CGPathRef badgePath = [self newBadgePathForTextSize:numberSize];
這里繪制的badgePath之后,是需要release. 有人說,我們不是使用了ARC么?它干嘛去了?關鍵時刻不出來釋放啦?還是它對這種情況不作處理的?
說對了.
The compiler does not automatically manage the lifetimes of Core Foundation objects; you must call CFRetain and CFRelease (or the corresponding type-specific variants) as dictated by the Core Foundation memory management rules (see Memory Management Programming Guide for Core Foundation).
就是我們類型是區分的core foundation(C語言的接口) 和object type(OC語言的接口)的類型是不一樣的,arc 只負責Objective-C type 的數據. 至于這2個的區別我后面會貼圖,大家一看自然懂
所以解決方案就是:
- 自己墻角蹲5min,然后默默把badgePath釋放掉
- 使用__bridge_transfer 其實就是將core foundation類型的數據轉為Objective-C類型的數據,本質就是指針轉換.
備注:這種牛逼的技術叫Toll-Free Bridging
參考如下:
Or you can use __bridge_transfer or CFBridgingRelease to move the ownership of the Core Foundation object to the under the Objective-C ARC object ownership.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.
ARC is responsible for relinquishing ownership of the object.
當然對于我而言自然就是 CGPathRelease(badgePath);
以上可能對很多高手來說是常識了罷了....
補充:
Toll-Free Bridging
https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Toll-FreeBridgin/Toll-FreeBridgin.html