亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

IOS中內存管理那些事

2020-07-26 03:32:12
字體:
來源:轉載
供稿:網友

Objective-C 和 Swift 語言的內存管理方式都是基于引用計數「Reference Counting」的,引用計數是一個簡單而有效管理對象生命周期的方式。引用計數分為手動引用計數「ARC: AutomaticReference Counting」和自動引用計數「MRC: Manual Reference Counting」,現在都是用 ARC 了,但是我們還是很有必要了解 MRC。

1. 引用計數的原理是什么?

當我們創建一個新對象時,他的引用計數為1;

當有一個新的指針指向這個對象時,他的引用計數就加1;

當對象關聯的某個指針不再指向他時,他的引用計數就減1;

當對象的引用計數為0時,說明此對象不再被任何指針指向,這時我們就可以將對象銷毀,回收內存。

由于引用計數簡單有效,除了 Objective-C 語言外,Microsoft 的 COM「Component Object Model」、C++11(基于引用計數的智能指針 share_prt)等語言也提供了基于引用計數的內存管理方式。

舉個例子:

新建工程,Xcode 默認開啟的是 ARC,我們這里針對「AppDelegate.m」文件使用 MRC,進行以下配置:

選擇目標工程,然后在「Build Phases」的「Compile Sources」下的「AppDelegate.m」文件配置編譯器參數「Compiler Flags」值為「-fno-objc-arc」

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  NSObject *objO = [NSObject new];  NSLog(@"Reference Count: %lu", (unsigned long)[objO retainCount]); // 1  NSObject *objB = [objO retain];  NSLog(@"Reference Count: %lu", (unsigned long)[objO retainCount]); // 2  [objO release];  NSLog(@"Reference Count: %lu", (unsigned long)[objO retainCount]); // 1  [objO release];  NSLog(@"Reference Count: %lu", (unsigned long)[objO retainCount]); // 1    [objO setValue:nil forKey:@"test"]; // 僵尸對象,向野指針發送消息會報錯(EXC_BAD_ACCESS)    return YES;}

Xcode 默認不會監控僵尸對象,這里我們配置開啟他,然后就可以看到具體的跟蹤信息了:

也可以通過選擇「Product」下的「Profile」來打開「Instruments」工具集。然后選擇「Zombies」,再單擊右下角的「Choose」按鈕進入檢測界面,這時點擊左上角的「Record」紅色圓點按鈕開始檢測。

1.1 上面例子,為什么最后一次通過 retainCount 獲取的值為1,而不是為0呢?

因為該對象的內存已經被回收,我們向一個被回收的對象發送 retainCount 消息,他的輸出結果是不確定的,如果該對象所占內存被復用了,那么就可能造成程序異常崩潰。

而且當最后一次執行 release 時,系統已經知道馬上要回收內存了,就沒必要再將 retainCount 減1,因為不管減不減1,該對象都會被回收,回收后他所在內存區域(包括 retainCount 值)就沒有意義了。不將retainCount 減1變為0,可以減少一次內存操作,加快對象的回收。

1.2 什么是僵尸對象、野指針、空指針呢?

僵尸對象:所占用內存已經被回收的對象,僵尸對象不能再使用。

野指針:指向僵尸對象(不可用內存)的指針,給野指針發送消息會報錯(EXC_BAD_ACCESS)。

空指針:沒有指向任何對象的指針(存儲的是 nil、NULL),給空指針發送消息不會報錯;空指針的一個經典使用場景就是在開發中獲取服務器 API 數據時,轉換野指針為空指針,避免發送消息報錯。

2. 為什么需要引用計數?

從上面簡單例子,我們還看不出引用計數真正的用處,因為該對象的生命周期只是在一個方法內。在真實的應用場景中,我們在方法內使用臨時對象,通常不需要修改他的引用計數,只需要在方法返回前銷毀對象就可以了。

然而,引用計數真正派上用場的場景是在面向對象的程序設計架構中,用于對象之間傳遞和共享數據。

舉個例子:

假如對象 A 生成了一個對象 O,需要調用對象 B 的某個方法,將對象 O 作為參數傳遞過去。

在沒有引用計數的情況下,一般內存管理的原則是「誰申請誰釋放」,那么對象 A 就需要在對象 B 不再需要對象 O 的時候,將對象 O 銷毀。但對象 B 可能臨時用一下對象 O,也可以覺得他重要,將他設置為自己的一個成員變量,在這種情況下,什么時候銷毀對象 O 就成了一個難題了。

對于以上情況有兩種做法:

(1)對象 A 在調用完對象 B 的某個方法之后,馬上銷毀參數對象 O,然后對象 B 需要將對象 O 復制一份,生成另一個對象 O2,同時自己來管理對象 O2 的生命周期。但是這種做法有一個很大的問題,就是他帶來更多的內存申請、復制、釋放的工作。本來可以復用的對象,因為不方便管理他的生命周期,就簡單地把他銷毀,又重新構造一份一樣的,實在太影響性能。

(2)對象 A 只負責生成對象 O,之后就由對象 B 負責完成對象 O 的銷毀工作。如果對象 B 只是臨時用一下對象 O,就可以用完后馬上銷毀,如果對象 B 需要長時間使用對象 O,就不銷毀他。這種做法看似解決了對象復制的問題,但是他強烈依賴于 A 和 B 兩個對象的配合,代碼維護者需要明確地記住這種編程約定。而且,由于對象 O 的生成和釋放在不同對象中,使得他的內存管理代碼分散在不同對象中,管理起來也很費勁。如果這個時候情況更加復雜一些,例如對象 B 需要再向對象 C 傳遞參數對象 O,那么這個對象在對象 C 中又不能讓對象 C 管理。所以這種方法帶來的復雜度更高,更加不可取。

引用計數的出現很好地解決這個問題,在參數對象 O 的傳遞過程中,哪些對象需要長時間使用他,就把他的引用計數加1,使用完就減1。所有對象遵守這個規則,對象的生命周期管理就可以完全交給引用計數了。我們也可以很方便地享受到共享對象帶來的好處。

2.1 什么是循環引用「Reference Cycles」問題,怎么解決呢?

引用計數這種內存管理方式雖然簡單,但有一個瑕疵就是他不能自動解決循環引用的問題。

舉個例子:

對象 A 和對象 B 相互引用對方作為自己的成員變量,只有當自己銷毀時,才將自己的成員變量的引用計數減1,因為對象 A 和對象 B 的銷毀相互依賴,這樣就造成我們所說的循環引用問題了。

循環引用會導致即使外界已經沒有任何指針能夠訪問他們了,但是他們所占資源仍然無法釋放的情況。

解決循環引用問題主要有兩種方法:

(1)明確知道哪里存在循環引用,合理時機主動斷開環中的一個引用,使得對象得以回收。這種方法不常用,因為他依賴開發人員自己手工顯式控制,相當于回到以前「誰申請誰釋放」的內存管理年代。

(2)使用弱引用「Weak Reference」,「weak」「__weak」類型,這種方法常用。弱引用雖然持有對象,但是并不增加他的引用計數。弱引用的一個經典使用場景就是委托代理「delegate」協議模式。

2.2 Xcode 中有什么工具可以檢測循環引用嗎?

在 Xcode 中有「Instruments」工具集可以很方便地檢測循環引用。

舉個例子:

- (void)viewDidLoad {  [super viewDidLoad];    NSMutableArray *mArrFirst = [NSMutableArray array];  NSMutableArray *mArrSecond = [NSMutableArray array];  [mArrFirst addObject:mArrSecond];  [mArrSecond addObject:mArrFirst];}

可以選擇「Product」下的「Profile」來打開「Instruments」工具集。

然后選擇「Leaks」,再單擊右下角的「Choose」按鈕進入檢測界面,這時點擊左上角的「Record」紅色圓點按鈕開始檢測。

3. Core Foundation 對象的內存管理

ARC 是編譯器特性,他不是運行時特性,更不是垃圾回收器「GC」。

ARC 能夠解決 iOS 開發中90%的內存管理問題,但是另外10%的內存管理問題是需要開發人員自己處理的,這主要是與底層 Core Foundation 對象交互的部分,底層 Core Foundation 對象由于不在 ARC 的管理下,所以需要自己維護這些對象的引用計數。

實際上 Core Foundation 對象使用的 CFRetain 和 CFRelease 方法,可以認為與 Objective-C 對象的 retain 和 release 方法等價,所以我們可以以 MRC 的方式進行類似管理。

3.1 在 ARC 中,通過什么方式可以把 Core Foundation 對象轉換為 Objective-C 對象呢?

轉換的過程,其實是告訴編譯器,對象的引用計數如何調整。

這里我們可以使用橋接「bridge」相關關鍵字來進行轉換工作,以下是這些(雙下劃線)關鍵字的說明:

(1)__bridge:只做類型轉換,不修改相關對象的引用計數,原來的 Core Foundation 對象在不用時,需要調用 CFRelease 方法。

(2)__bridge_retained:類型轉換后,將相關對象的引用計數加1,原來的 Core Foundation 對象在不用時,需要調用 CFRelease 方法。

(3)__bridge_transfer:類型轉換后,將相關對象的引用計數交給 ARC 管理,原來的 Core Foundation 對象在不用時,不需要調用 CFRelease 方法。

我們根據具體的業務邏輯,合理使用上面的三種轉換關鍵字,就可以解決Core Foundation 對象 與 Objective-C 對象相對轉換的問題了。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人av网址| 97久久精品在线| 久久91亚洲精品中文字幕| 色综合老司机第九色激情| 国产精品精品一区二区三区午夜版| 狠狠躁天天躁日日躁欧美| 成人久久18免费网站图片| 51ⅴ精品国产91久久久久久| 中文字幕免费国产精品| 亚洲欧洲av一区二区| 国产精品福利网| 国产精品成久久久久三级| 亚洲国产成人久久综合| 欧美成人精品三级在线观看| 伊人亚洲福利一区二区三区| 亚洲欧美中文字幕| 亚洲伊人成综合成人网| 欧美与欧洲交xxxx免费观看| 成人国产精品一区二区| 亚洲老板91色精品久久| 清纯唯美日韩制服另类| 亚洲精品中文字幕av| 亚洲色图偷窥自拍| 在线精品国产成人综合| 精品精品国产国产自在线| 久久久av免费| 色综合久久久888| 免费不卡在线观看av| 亚洲图片在线综合| 欧美黑人一级爽快片淫片高清| 91精品在线看| 色综合色综合久久综合频道88| 亚洲精品在线观看www| 中文字幕日韩免费视频| 亚洲新声在线观看| 亚洲第一男人天堂| 亚洲国产欧美一区二区丝袜黑人| 久久免费视频网| 51精品在线观看| 日韩欧美精品中文字幕| 亚洲欧美日韩爽爽影院| 91福利视频网| 中文欧美在线视频| 在线播放国产一区中文字幕剧情欧美| 97在线视频一区| 久久不射热爱视频精品| 国产精品亚洲激情| 少妇久久久久久| 欧美精品videosex性欧美| 456国产精品| 国产欧美日韩免费| 久久久久久香蕉网| 亚洲国产精品成人va在线观看| 久久精品中文字幕| 亚洲xxx大片| 这里只有精品在线播放| 久久噜噜噜精品国产亚洲综合| 日韩三级成人av网| 影音先锋欧美精品| 成人免费淫片视频软件| 九色精品免费永久在线| 97精品国产97久久久久久春色| 久久精品国产亚洲精品2020| 高清一区二区三区四区五区| 欧美日韩国产成人在线| 欧美一级视频在线观看| 亚洲伊人第一页| 欧美日韩国产中文精品字幕自在自线| 亚洲天堂av在线播放| 国模精品一区二区三区色天香| 日韩av片永久免费网站| 国产大片精品免费永久看nba| 爱福利视频一区| 亚洲国产成人一区| 精品亚洲永久免费精品| 欧美第一页在线| 国产成人高清激情视频在线观看| 国产精品久久久久久超碰| 亚洲国产高清自拍| 欧美激情国产精品| 奇门遁甲1982国语版免费观看高清| 91欧美精品成人综合在线观看| 欧美日韩中国免费专区在线看| 欧美日韩精品在线视频| 亚洲新中文字幕| 国产亚洲美女精品久久久| 国产在线a不卡| 精品在线小视频| 日韩精品免费在线视频观看| 久久精品国产亚洲一区二区| 日本精品性网站在线观看| 欧美极品美女视频网站在线观看免费| 久久免费少妇高潮久久精品99| 51午夜精品视频| …久久精品99久久香蕉国产| 亚洲欧洲日产国产网站| 精品国产电影一区| www.日韩av.com| 热久久免费国产视频| 欧美黑人巨大精品一区二区| 最近免费中文字幕视频2019| 久久久久久久久久婷婷| 国内偷自视频区视频综合| 亚洲va国产va天堂va久久| 日本国产一区二区三区| 色老头一区二区三区在线观看| 国产精品精品视频一区二区三区| 97国产精品人人爽人人做| 精品福利免费观看| 欧美亚洲激情在线| 午夜免费久久久久| 欧美老女人性视频| 国产成人a亚洲精品| 欧美日韩999| 欧美最猛性xxxxx(亚洲精品)| 成人a在线视频| 国产一区二区三区视频在线观看| 国产91色在线免费| 国产专区欧美专区| 在线亚洲国产精品网| 国产成人精品电影久久久| 在线播放国产精品| 成人国产在线视频| 欧美激情视频三区| 夜夜嗨av一区二区三区四区| 欧美在线性爱视频| 一本色道久久88综合日韩精品| 国产精品久久久久久久app| 亚洲韩国欧洲国产日产av| 亚洲伊人成综合成人网| 国产精品影院在线观看| 久久精品中文字幕一区| 欧美在线一区二区三区四| 久久99久久99精品中文字幕| 成人免费网站在线看| 欧美人在线视频| 欧美成人免费播放| 欧美性xxxx极品hd满灌| 日韩大片在线观看视频| 日本成人免费在线| 成人写真福利网| 亚洲综合在线做性| 26uuu日韩精品一区二区| 日韩少妇与小伙激情| 国产精品自拍小视频| 欧美视频二区36p| 中文欧美日本在线资源| 日韩欧美在线中文字幕| 91亚洲精品在线观看| 国产精品igao视频| 午夜精品一区二区三区在线| 日韩中文字幕视频在线| 国产精品私拍pans大尺度在线| 免费99精品国产自在在线| 国产精品羞羞答答| 九九视频这里只有精品| 国产视频在线一区二区| 性欧美办公室18xxxxhd| 国产精品福利久久久| 国产情人节一区| 国产精品爽黄69天堂a| 日韩精品极品视频免费观看| 欧美裸体xxxx极品少妇| 最近2019中文字幕一页二页|