《Objective-C高級編程-iOS與OS+X多線程和內(nèi)存管理》讀書筆記

Objective-C高級編程-iOS與OS+X多線程和內(nèi)存管理

第一章:自動引用計(jì)數(shù)

  • 自己生成的對象婶希,自己所持有。
  • 非自己生成的對象,自己也能持有
  • 不再需要自己持有的對象時釋放
  • 非自己持有的對象無法釋放
對象操作 Objective-C方法
生成并持有對象 alloc/new/copy/mutableCopy等
持有對象 retain
釋放對象 release
廢棄對象 dealloc

Cocoa 框架中 Foundation 框架類庫的 NSObject 類擔(dān)負(fù)內(nèi)存管理的職責(zé)。

自己生成的對象涯贞,自己所持有

使用以下名稱開頭的方法名意味著自己生成的對象只有自己持有:

  • alloc
  • new
  • copy
  • mutableCopy

使用 NSObject 類的 alloc 類方法就能自己生成并持有對象。另外危喉,使用 new 類方法也能生成并持有對象宋渔。[NSObject new][[NSObject alloc] init] 是完全一致的

非自己生成的對象,自己也能持有

用上述方法之外的方法取得的對象即用 alloc/new/copy/mutableCopy 以外的方法取得的對象辜限,因?yàn)榉亲约荷刹⒊钟谢始穑宰约翰皇窃搶ο蟮某钟姓摺@?NSArray 類的 array 類方法薄嫡。通過 retain 方法审磁,非自己生成的對象成為了自己所持有的。

不再需要自己持有的對象時釋放

自己持有的對象岂座,一旦不再需要态蒂,持有者有義務(wù)釋放該對象,釋放使用的是 release 方法费什。
alloc/new/copy/mutableCopy 方法生成并持有的對象钾恢,或者用 retain 方法持有的對象,一旦不再需要鸳址,務(wù)必要用 release 方法進(jìn)行釋放

autorelease 提供這樣的功能瘩蚪,使對象再超出指定的生存范圍時能夠自動并正確地釋放(調(diào)用release方法)

Xnip2019-08-30_21-48-42

無法釋放非自己持有的對象

對于用 alloc/new/copy/mutableCopy 方法生成并持有的對象,或者用 retain 方法持有的對象稿黍,由于持有者是自己疹瘦,所以在不需要該對象時需要將其釋放。而由此以外所得到的對象絕對不能釋放巡球。倘若在應(yīng)用程序中釋放了非自己所持有的對象就會造成崩潰言沐。

  • Objective-C 的對象中存有引用技術(shù)這一整數(shù)值邓嘹。
  • 調(diào)用 alloc 或是 retain 方法后,引用計(jì)數(shù)值加 1.
  • 調(diào)用 release 后险胰,引用技術(shù)減 1.
  • 引用計(jì)數(shù)值為 0 時汹押,調(diào)用 dealloc 方法廢棄對象。

蘋果對引用計(jì)數(shù)大概是采用 散列表(引用計(jì)數(shù)表)來管理引用計(jì)數(shù)

GNUstep 將引用計(jì)數(shù)保存在對象占用內(nèi)存塊頭部的變量中起便,而蘋果則是保存在引用計(jì)數(shù)表的記錄中棚贾。

通過內(nèi)存塊頭部管理引用計(jì)數(shù)的好處:

  • 少量代碼即可完成
  • 能夠統(tǒng)一管理引用計(jì)數(shù)用內(nèi)存塊與對象用內(nèi)存塊

通過引用計(jì)數(shù)表管理引用計(jì)數(shù)的好處:

  • 對象用內(nèi)存塊的分配無序考慮內(nèi)存塊頭部
  • 引用計(jì)數(shù)表各記錄中存有內(nèi)存塊地址,可從各個記錄追溯到各對象的內(nèi)存塊

在利用工具檢測內(nèi)存泄露時榆综,引用計(jì)數(shù)表的各記錄也有助于檢測各對象的持有者是否存在妙痹。

autorelease

autorelease 就是自動釋放,這看上去很像 ARC 鼻疮,實(shí)際上更類似于 C 語言中自動變量(局部)變量的特性怯伊。
C 語言的自動變量特性:程序執(zhí)行時,若某自動變量超出其作用域陋守,該自動變量將被自動廢棄。
與 C 語言的自動變量不同的是利赋,編程人員可以設(shè)定變量的作用域水评。
autorelease 的具體使用方法如下:

  1. 生成并持有 NSAutoreleasePool 對象
  2. 調(diào)用已分配對象的 autorelease 實(shí)例方法
  3. 廢棄 NSAutoreleasePool 對象
Xnip2019-09-01_11-59-29

NSAutoreleasePool 對象的生存周期相當(dāng)于 C 語言變量的作用域。對于所有調(diào)用過 autorelease 實(shí)例方法的對象媚送,在廢棄NSAutoreleasePool 對象時中燥,都將調(diào)用 release 實(shí)例方法。
在大量產(chǎn)生 autorelease 對象時塘偎,需要在適當(dāng)?shù)牡胤缴闪粕妗⒊钟谢驈U棄 NSAutoreleasePool 對象。
調(diào)用 NSObject 類的 autorelease 實(shí)例方法吟秩,該對象將被追加到正在使用的 NSAutoreleasePool 對象中的數(shù)組里咱扣。即 本質(zhì)就是調(diào)用 NSAutoreleasePool 對象的 addObject 類方法。

ARC 規(guī)則

循環(huán)引用容易發(fā)生內(nèi)存泄露涵防,所謂內(nèi)存泄露就是應(yīng)當(dāng)廢棄的對象在超出其生存周期后繼續(xù)存在闹伪。使用__weak修飾符可避免循環(huán)引用,__weak修飾符與__strong修飾符 相反壮池,提供弱引用偏瓤。弱引用不能持有對象實(shí)例,因?yàn)?code>__weak修飾符的變量不吃又對象椰憋,所以在超出其變量作用域時厅克,對象即被釋放。
__weak修飾符還有另一優(yōu)點(diǎn):在持有對象的弱引用時橙依,若該對象被被廢棄证舟,則此弱引用將自動失效且處于 nil 被賦值的狀態(tài)硕旗。

在 ARC 有效的情況下編譯源代碼需遵守如下規(guī)則:

  • 不能使用 retain/release/retainCount/autorelease
  • 不能使用 NSAllocateObject / NSDeallocateObject
  • 須遵守內(nèi)存管理的方法命名規(guī)則
  • 不要顯式調(diào)用 dealloc
  • 使用 @autoreleasepoll 塊替代 NSAutoreleasePool
  • 不能使用區(qū)域 (NSZone)
  • 對象型變量不能作為 C 語言結(jié)構(gòu)體(struct/union)的成員
  • 顯式轉(zhuǎn)換 idvoid * , 通過 (__bridge void *)(__bridge id) 進(jìn)行橋接

__weak 修飾符

weak 表與引用計(jì)數(shù)表相同褪储,作為散列表被實(shí)現(xiàn)卵渴。如果使用 weak 表,將廢棄對象的變量的地址作為鍵值進(jìn)行檢索鲤竹,就能高速地獲取對應(yīng)的附有 __weak 修飾符的變量的地址浪读。另外,由于一個對象可同時賦值給多個附有 __weak 修飾符的變量中辛藻,所以對于一個鍵值碘橘,可注冊多個變量的地址。

如果附有 __weak 修飾符的變量所引用的對象被廢棄吱肌,則將 nil 賦值給該變量的步驟:

  1. 從 weak 表中獲取廢棄對象的地址為鍵值的記錄
  2. 將包含在記錄中的所有附有 __weak 修飾符的變量的地址痘拆,賦值為 nil.
  3. 從 weak 表中刪除該記錄
  4. 從引用計(jì)數(shù)表中刪除廢棄對象的地址為鍵值的記錄

如果大量使用附有 __weak 修飾符的變量,會消耗相應(yīng)的 CPU 資源氮墨,良策是只在需要避免循環(huán)引用時使用 __weak 修飾符纺蛆。

第二章:Blocks

Blocks 是 C語言的擴(kuò)充功能,用一句話表示:帶有自動變量(局部變量)的匿名函數(shù)规揪。
Block 語法:
^ 返回值類型 參數(shù)列表 表達(dá)式

使用附有 __block 說明符修飾的自動變量可在 Block 中賦值桥氏,該變量成為 __block 變量

在Block中,截獲自動變量的方法并沒有實(shí)現(xiàn)對C語言數(shù)組的截獲猛铅,這時使用指針可以解決問題字支。

Blocks 的實(shí)現(xiàn)

Block 本質(zhì)是一個 OC 對象,它內(nèi)部也有一個 isa 指針奸忽。是封裝了函數(shù)調(diào)用和函數(shù)調(diào)用環(huán)境的 OC 對象堕伪。

iOS 類的本質(zhì)即 class_t 結(jié)構(gòu)體:

struct class_t {
   struct class_t *isa;
   struct class_t *superclass;
   Cache cache;
   IMP *vtable;
   uintptr_t data_NEVER_USE;
}

該實(shí)例名稱持有聲明的成員變量、方法的名稱栗菜、方法的實(shí)現(xiàn)(即函數(shù)指針)欠雌、屬性以及父類的指針。
Block 即為 Objective-C 的對象疙筹。

Block 的三種類型

設(shè)置對象的存儲域 備注
_NSConcreteStackBlock 捕獲局部變量
_NSConcreteGlobalBlock 程序的數(shù)據(jù)區(qū)域(.data 區(qū)) 不捕獲自動變量
_NSConcreteMallocBlock 捕獲成員變量

Block 何時會復(fù)制到堆

  • 調(diào)用 Block 的 copy 實(shí)例方法時
  • Block 作為函數(shù)返回值返回時
  • 將 Block 賦值給附有 __strong 修飾符 id 類型的類或 Block 類型成員變量時
  • 在方法名中含有 usingBlock 的 Cocoa 框架方法或 GCD 的 API 中傳遞 Block 時桨昙。

第三章:Grand Central Dispatch

Grand Central Dispatch (GCD) 是異步執(zhí)行任務(wù)的技術(shù)之一,一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級中實(shí)現(xiàn)腌歉,開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)?Dispatch Queue 中蛙酪,GCD 就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)。

多線程編程可能會出現(xiàn)的問題:

  • 多個線程更新相同的資源會導(dǎo)致數(shù)據(jù)的不一致(數(shù)據(jù)競爭)- 解決:使用 Serial Dispatch Queue (串行隊(duì)列)
  • 停止等待事件的線程會導(dǎo)致多個線程相互持續(xù)等待(死鎖)
  • 使用太多線程會消耗大量內(nèi)存

Dispatch Queue 按照追加的順序(先進(jìn)先出 FIFO)執(zhí)行處理翘盖,另在執(zhí)行處理時存在兩種 Dispatch Queue :一種是等待現(xiàn)在執(zhí)行中處理的 Serial Dispatch Queue桂塞,另一種是不等待現(xiàn)在執(zhí)行中處理的 Concurrent Dispatch Queue。

GCD API

可使用 dispatch_set_target_queue API 設(shè)置 Dispatch Queue 的優(yōu)先級馍驯,同時也可以使多個本應(yīng)并行執(zhí)行的多個 Serial Dispatch Queue阁危,在目標(biāo) Serial Dispatch Queue 上串行執(zhí)行玛痊。

dispatch_after 函數(shù)并不準(zhǔn)時
因?yàn)?Main Dispatch Queue 在主線程的 Runloop 中執(zhí)行,所以在比如每隔 1/60 秒自行的 Runloop 中狂打,Block 最快3秒后自行擂煞,最慢在3秒 + 1/60 秒后執(zhí)行,并且在 Main Dispatch Queue 有大量處理追加或主線程的處理本身有延遲時趴乡,這個時間會更長对省。

Dispatch Group 在追加到 Dispatch Queue 中的多個處理全部結(jié)束后想執(zhí)行結(jié)束處理可使用 Dispatch Group 實(shí)現(xiàn)。

dispatch_sync 如同簡易版的 dispatch_group_wait 函數(shù)晾捏,會在指定隊(duì)列中同步執(zhí)行任務(wù)蒿涎,在任務(wù)執(zhí)行結(jié)束之前不會返回。如果在主線程同步執(zhí)行 Block 就會出現(xiàn)死鎖惦辛。

dispatch_apply 函數(shù)可進(jìn)行快速遍歷劳秋。由于 dispatch_apply 函數(shù)與 dispatch_sync 函數(shù)相同,會等待處理執(zhí)行結(jié)束胖齐,因此推薦在 dispatch_async 函數(shù)中非同步地執(zhí)行 dispatch_apply 函數(shù)玻淑。

dispatch_suspend 函數(shù)可暫時掛起指定的 Dispatch Queue。
dispatch_resume 函數(shù)可恢復(fù)指定的 Dispatch Queue呀伙。

dispatch_semaphore 函數(shù)可對操作進(jìn)行更細(xì)粒度的排他控制补履。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait 函數(shù)等待 Dispatch Semaphore 的計(jì)數(shù)值達(dá)到大于或等于1. 該處理結(jié)束是使用 dispatch_semaphore_signal 函數(shù)將 Dispatch Semaphore 的計(jì)數(shù)值加1.

dispatch_once 函數(shù)是保證再應(yīng)用程序執(zhí)行中只執(zhí)行一次指定處理的 API。

dispatch_IO 函數(shù)可多線程并發(fā)處理大文件区匠,以提高文件讀取速度干像。

GCD 實(shí)現(xiàn)

Block 并不是直接加入 FIFO 隊(duì)列中帅腌,而是先加入 Dispatch Continuation 這一 dispatch_continuation_t 類型結(jié)構(gòu)體中驰弄,然后再加入 FIFO 隊(duì)列。用于記憶 Block 所屬的 Dispatch Group 喝其他一些信息速客,通常叫上下文戚篙。

。溺职。岔擂。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浪耘,隨后出現(xiàn)的幾起案子乱灵,更是在濱河造成了極大的恐慌,老刑警劉巖七冲,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痛倚,死亡現(xiàn)場離奇詭異,居然都是意外死亡澜躺,警方通過查閱死者的電腦和手機(jī)蝉稳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門抒蚜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耘戚,你說我怎么就攤上這事嗡髓。” “怎么了收津?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵扮念,是天一觀的道長雷则。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么踪蹬? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮哟忍,結(jié)果婚禮上鹅髓,老公的妹妹穿的比我還像新娘。我一直安慰自己廓八,他們只是感情好奉芦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剧蹂,像睡著了一般声功。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宠叼,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天先巴,我揣著相機(jī)與錄音,去河邊找鬼冒冬。 笑死伸蚯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的简烤。 我是一名探鬼主播剂邮,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼横侦!你這毒婦竟也來了挥萌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤枉侧,失蹤者是張志新(化名)和其女友劉穎引瀑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榨馁,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憨栽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徒像。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡黍特,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锯蛀,到底是詐尸還是另有隱情灭衷,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布旁涤,位于F島的核電站翔曲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏劈愚。R本人自食惡果不足惜瞳遍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望菌羽。 院中可真熱鬧掠械,春花似錦、人聲如沸注祖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽是晨。三九已至肚菠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罩缴,已是汗流浹背蚊逢。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留箫章,地道東北人烙荷。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像炉抒,于是被迫代替她去往敵國和親奢讨。 傳聞我的和親對象是個殘疾皇子稚叹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容