iOS內(nèi)存管理

馮·諾依曼體系:運(yùn)算器 控制器 存儲器 輸入與輸出

內(nèi)存即存儲器呛伴,用來存儲指令與數(shù)據(jù)

注:哈佛體系與普林斯頓體系的不同,使用兩個獨(dú)立的存儲器模塊,分別存儲指令和數(shù)據(jù),每個存儲模塊都不允許指令和數(shù)據(jù)并存褐鸥;使用獨(dú)立的兩條總線,分別作為CPU與每個存儲器之間的專用通信路徑赐稽,而這兩條總線之間毫無關(guān)聯(lián)叫榕。

物理地址:存儲器每一個字節(jié)單元給一個唯一的存儲器地址,即為物理地址又憨,又叫實(shí)際地址或絕對地址翠霍。

虛擬存儲系統(tǒng):操作系統(tǒng)層面做了一個物理地址與邏輯地址之間的映射。使用虛擬地址蠢莺,作為讀寫的一部分寒匙。

1.程序可以使用一系列相鄰的虛擬地址來訪問物理內(nèi)存中不相鄰的大內(nèi)存緩沖區(qū)。

2.程序可以使用一系列虛擬地址來訪問大于可用物理內(nèi)存的內(nèi)存緩沖區(qū)躏将。當(dāng)物理內(nèi)存的供應(yīng)量變小時锄弱,內(nèi)存管理器會將物理內(nèi)存頁(通常大小為4KB)保存到磁盤文件。數(shù)據(jù)或代碼頁會根據(jù)需要在物理內(nèi)存與磁盤之間移動祸憋。

3.不同進(jìn)程使用的虛擬地址彼此隔離会宪。一個進(jìn)程中的代碼無法更改正在由另一進(jìn)程或操作系統(tǒng)使用的物理內(nèi)存。

解決兩個問題蚯窥,一是多個程序同時運(yùn)行掸鹅,二是占用很大內(nèi)存的程序塞帐。

一個程序在運(yùn)行時,實(shí)際要用到的指令和數(shù)據(jù)都是很有限的巍沙,不可能從頭到尾同時用葵姥。那么對于一個程序來說,假裝自己有非常大的空間句携,實(shí)際上只要有條理的把暫時要用到的部分放進(jìn)物理內(nèi)存供CPU訪問就好榔幸,這樣第二個問題解決了。那既然每個程序(進(jìn)程)只用一小塊矮嫉,那整個物理內(nèi)存就可以分給多個程序(進(jìn)程)用了削咆,第一個問題也迎刃而解。當(dāng)然蠢笋,這樣做的前提是拨齐,數(shù)據(jù)和指令的動態(tài)進(jìn)出,用完了的暫時不用的踢出內(nèi)存昨寞,需要用的及時加載進(jìn)來奏黑。

內(nèi)存泄漏:動態(tài)存儲分配的空間,在使用完畢后未釋放编矾,結(jié)果導(dǎo)致一直占用該內(nèi)存單元熟史,直到程序結(jié)束。

內(nèi)存溢出:沒有內(nèi)存可用窄俏。

內(nèi)存可細(xì)分五部分組成

代碼(指令):靜態(tài)蹂匹,就是只讀的東西。

初始化數(shù)據(jù):有初始值的變量,常量。

未初始化數(shù)據(jù):只聲明未給值得變量万搔。

棧:程序運(yùn)行記錄,每個線程履植,也就是每個執(zhí)行序列各有一個,都是編譯時候能確定好的悄晃,這里面的數(shù)據(jù)可以不使用指針也不會丟玫霎。

堆:最靈活,動態(tài)分配和釋放妈橄,編譯時不能確定庶近,OC對象都存在堆里,通常都是用指針訪問 指針從線程棧中來眷蚓,但不獨(dú)屬于某個線程鼻种,誰分配誰釋放說的是堆上對象的管理。

IOS內(nèi)存管理

iOS的內(nèi)存管理也是在以上的大框架下

最大的不同就是物理內(nèi)存警告時

物理內(nèi)存警告時沙热,IOS會把能通過映射重新加載的內(nèi)容直接清理出內(nèi)存叉钥,對于不可再生的數(shù)據(jù)罢缸,iOS需要App進(jìn)程配合處理,向各進(jìn)程發(fā)送內(nèi)存警告要求配合釋放內(nèi)存投队,對于不能及時釋放足夠內(nèi)存的祖能,直接kill掉進(jìn)程,必要時甚至是前臺運(yùn)行的應(yīng)用蛾洛。

iOS內(nèi)存管理機(jī)制的原理是引用計(jì)數(shù),引用計(jì)數(shù)簡單來說就是統(tǒng)計(jì)一塊內(nèi)存的所有權(quán)雁芙,當(dāng)這塊內(nèi)存被創(chuàng)建出來的時候轧膘,它的引用計(jì)數(shù)從0增加到1,表示有一個對象或指針持有這塊內(nèi)存兔甘,擁有這塊內(nèi)存的所有權(quán)谎碍,如果這時候有另外一個對象或指針指向這塊內(nèi)存,那么為了表示這個后來的對象或指針對這塊內(nèi)存的所有權(quán)洞焙,引用計(jì)數(shù)加1變?yōu)?蟆淀,之后若有一個對象或指針不再指向這塊內(nèi)存時,引用計(jì)數(shù)減1澡匪,表示這個對象或指針不再擁有這塊內(nèi)存的所有權(quán)熔任,當(dāng)一塊內(nèi)存的引用計(jì)數(shù)變?yōu)?,表示沒有任何對象或指針持有這塊內(nèi)存唁情,系統(tǒng)便會立刻釋放掉這塊內(nèi)存疑苔。

其中在開發(fā)時引用計(jì)數(shù)又分為ARC(自動內(nèi)存管理)和MRC(手動內(nèi)存管理)。ARC的本質(zhì)其實(shí)就是MRC甸鸟,只不過是系統(tǒng)幫助開發(fā)者管理已創(chuàng)建的對象或內(nèi)存空間惦费,自動在系統(tǒng)認(rèn)為合適的時間和地點(diǎn)釋放掉已經(jīng)失去作用的內(nèi)存空間,原理是一樣的抢韭。雖然ARC操作起來很方便薪贫,不但減少了代碼量,而且降低了內(nèi)存出錯的概率刻恭,但因?yàn)锳RC不一定會及時釋放瞧省,所以程序有時候可能會占用內(nèi)存較大。而MRC若做得好鳍贾,通過手動管理臀突,及時釋放掉不需要的內(nèi)存空間,便可保證程序長時間運(yùn)行在良好狀態(tài)上贾漏。

在MRC中會引起引用計(jì)數(shù)變化的關(guān)鍵字有:alloc候学,retain,copy纵散,release梳码,autorelease隐圾。(strong關(guān)鍵字只用于ARC,作用等同于retain)

alloc:當(dāng)一個類的對象創(chuàng)建掰茶,需要開辟內(nèi)存空間的時候暇藏,會使用alloc,alloc是一個類方法濒蒋,只能用類調(diào)用盐碱,它的作用是開辟一塊新的內(nèi)存空間,并使這塊內(nèi)存的引用計(jì)數(shù)從0增加到1沪伙,注意瓮顽,是新的內(nèi)存空間,每次用類alloc出來的都是一塊新的內(nèi)存空間围橡,與上一次alloc出來的內(nèi)存空間沒有必然聯(lián)系暖混,而且上一次alloc出來的內(nèi)存空間仍然存在,不會被釋放翁授。

retain:retain是一個實(shí)例方法拣播,只能由對象調(diào)用,它的作用是使這個對象的內(nèi)存空間的引用計(jì)數(shù)加1收擦,并不會新開辟一塊內(nèi)存空間贮配,通常于賦值是調(diào)用,如:

對象2=[對象1 retain]塞赂;表示對象2同樣擁有這塊內(nèi)存的所有權(quán)牧嫉。若只是簡單地賦值,如:對象2=對象1减途;那么當(dāng)對象1的內(nèi)存空間被釋放的時候酣藻,對象2便會成為野指針,再對對象2進(jìn)行操作便會造成內(nèi)存錯誤鳍置。

copy:copy同樣是一個實(shí)例方法辽剧,只能由對象調(diào)用,返回一個新的對象税产,它的作用是復(fù)制一個對象到一塊新的內(nèi)存空間上怕轿,舊內(nèi)存空間的引用計(jì)數(shù)不會變化,新的內(nèi)存空間的引用計(jì)數(shù)從0增加到1辟拷,也就是說撞羽,雖然內(nèi)容一樣,但實(shí)質(zhì)上是兩塊內(nèi)存衫冻,相當(dāng)于克隆诀紊,一個變成兩個。其中copy又分為淺拷貝隅俘、深拷貝和真正的深拷貝邻奠,淺拷貝只是拷貝地址與retain等同笤喳;深拷貝是拷貝內(nèi)容,會新開辟新內(nèi)存碌宴,與retain不一樣杀狡;真正的深拷貝是對于容器類來說的,如數(shù)組類贰镣、字典類和集合類(包括可變和不可變)呜象,假設(shè)有一個數(shù)組類對象,普通的深拷貝會開辟一塊新內(nèi)存存放這個對象碑隆,但這個數(shù)組對象里面的各個元素的地址卻沒有改變也就是說數(shù)組元素只是進(jìn)行了retain或者淺拷貝而已恭陡,并沒有創(chuàng)建新的內(nèi)存空間,而真正的深拷貝干跛,不但數(shù)組對象本身進(jìn)行了深拷貝,連數(shù)組元素都進(jìn)行了深拷貝祟绊,即為各個數(shù)組元素開辟了新的內(nèi)存空間楼入。

release:release是一個實(shí)例方法,同樣只能由對象調(diào)用牧抽,它的作用是使對象的內(nèi)存空間的引用計(jì)數(shù)減1嘉熊,若引用計(jì)數(shù)變?yōu)?則系統(tǒng)會立刻釋放掉這塊內(nèi)存。如果引用計(jì)數(shù)為0的基礎(chǔ)上再調(diào)用release扬舒,便會造成過度釋放阐肤,使內(nèi)存崩潰;

autorelease:autorelease是一個實(shí)例方法讲坎,同樣只能由對象調(diào)用孕惜,它的作用于release類似,但不是立刻減1晨炕,相當(dāng)于一個延遲的release衫画,通常用于方法返回值的釋放,如便利構(gòu)造器瓮栗。autorelease會在程序走出自動釋放池時執(zhí)行削罩,通常系統(tǒng)會自動生成自動釋放池(即使是MRC下),也可以自己設(shè)定自動釋放池

引用計(jì)數(shù)(reference counting)

OC中每一個對象有一個關(guān)聯(lián)的整數(shù)retainCount用于記錄對象的使用情況费奸,當(dāng)retainCount為0時弥激,對象被銷毀。

alloc copy new retain 等會使retainCount +1,

release會 -1

NSString 實(shí)際上是一個字符型常量愿阐,是沒有引用計(jì)數(shù)的

賦值操作是不會擁有對象的微服,引用計(jì)數(shù)不會加一,要持有對象需retain

引用計(jì)數(shù)不為0缨历,因?yàn)橐糜?jì)數(shù)為1的對象release時职辨,系統(tǒng)對該對象回收盗蟆,不做減一操作。

自動釋放池

不確定一個對象什么時候不再使用

autorelease 自動在未來釋放

原理:把對象添加到自動釋放池舒裤,當(dāng)自動釋放池銷魂時喳资,會對池中所有的對象發(fā)送release消息。

自動釋放池的創(chuàng)建

注:

1.自動釋放池只是給池中所有的對象發(fā)送release消息腾供,當(dāng)對象的引用計(jì)數(shù)>1時仆邓,對象無法銷毀。

2.autorelease不會改變對象的引用計(jì)數(shù)

ARC

ios5 引入ARC(Auto Reference Counting)

編譯時特性伴鳖,不是運(yùn)行時特性节值,更不是垃圾回收器

自動引用計(jì)數(shù),在編譯時榜聂,自動加上retain release等搞疗,實(shí)現(xiàn)內(nèi)存管理。

ARC開啟:可以在工程選項(xiàng)中選擇Targets -> Compile Phases -> Compile Sources须肆,在里面找到對應(yīng)文件匿乃,添加flag: -fobjc-arc

關(guān)閉:-fno-objc-arc? ;打開:-fobjc-arc

ARC IOS5開始引入豌汇,現(xiàn)在絕大部分開發(fā)都是ARC模式幢炸,以下應(yīng)用主要是針對ARC模式下的應(yīng)用。

屬性的內(nèi)存管理

1.assign: 一般修飾基本數(shù)據(jù)類型

2.retain: release舊值拒贱,再retain新值

使用set方法宛徊,實(shí)質(zhì)上會先保留新值,再釋放舊值逻澳,再設(shè)置新值闸天,避免新舊值一樣時導(dǎo)致對象被釋放。

MRC寫法:

ARC寫法:

3.copy: release舊值斜做,再copy新值(copy內(nèi)容)

一般修飾 NSString号枕、NSArray、NSDictionary等需要保護(hù)其封裝性的對象陨享。尤其是在其內(nèi)容可變的情況下 因此會拷貝一份內(nèi)容給屬性使用葱淳,避免可能造成的對源內(nèi)容進(jìn)行改動

block一般使用copy修飾

4.weak ARC新引入 可代替assign,比assign多了一個特性(置nil)

delegate 一般用weak修飾,避免循環(huán)引用

set方法時抛姑,只設(shè)置新值

5.strong ARC新引入 可代替retain

block的內(nèi)存管理

1.循環(huán)引用

block一般用copy修飾赞厕,當(dāng)block又引用了對象的其他成員變量時,就會對這個變量本身產(chǎn)生強(qiáng)引用定硝,那么變量本身和它自己的block就形成了循環(huán)引用皿桑。

__weak typeof (self) weakSelf = self;

ARC下要生成一個對自身的弱引用,表示block別再對self對象retain了,避免循環(huán)引用

2.block內(nèi)部變量

1.block不能改變局部變量诲侮,要改變時需加__block修飾

2.block可改變?nèi)肿兞?/p>

3.static變量也可在block中修改

內(nèi)存問題的分析解決

1.僵尸對象和野指針

僵尸對象:內(nèi)存被回收的對象

野指針:指向僵尸對象的指針镀虐,向野指針發(fā)送消息對導(dǎo)致崩潰EXC_BAD_ACCESS

1 在product-scheme-edit scheme-diagnostics中將enable zombie objects勾選上,下次再出現(xiàn)這樣的錯誤就可以準(zhǔn)確定位了沟绪。

2 在Xcode-open developer tool-Instruments打開工具集刮便,選擇Zombies工具可以對已安裝的應(yīng)用進(jìn)行僵尸對象檢測。

2.循環(huán)引用

1)在product-Analyze中使用靜態(tài)分析來檢測代碼中可能存在循環(huán)引用的問題绽慈。

2)在Xcode-open developer tool-Instruments打開工具集恨旱,選擇Leaks工具可以對已安裝的應(yīng)用進(jìn)行內(nèi)存泄漏檢測,此工具能檢測靜態(tài)分析不會提示坝疼,但是到運(yùn)行時才會出現(xiàn)的內(nèi)存泄漏問題搜贤。

3.循環(huán)中對象占用內(nèi)存大

循環(huán)內(nèi)產(chǎn)生大量的臨時對象,直至循環(huán)結(jié)束才釋放钝凶,可能導(dǎo)致內(nèi)存泄漏仪芒。

解決方法:在循環(huán)中創(chuàng)建自己的autoReleasePool,及時釋放占用內(nèi)存大的臨時變量耕陷,減少內(nèi)存占用峰值掂名。

4.內(nèi)存泄漏

通過Analyze來進(jìn)行靜態(tài)代碼檢查,以發(fā)現(xiàn)在語法上顯而易見的內(nèi)存泄露問題

內(nèi)存泄露是運(yùn)行時的問題啃炸,這時可用Instruments中的Allocation和Leaks來不斷重復(fù)操作App铆隘,發(fā)現(xiàn)和定位內(nèi)存泄露點(diǎn)

5.過度釋放

原則上都會直接crash(然而由于某些特殊的情況卓舵,不會馬上crash)南用。

對于這種問題,可以直接使用Zombie掏湾,當(dāng)過度釋放發(fā)生時會立即停在發(fā)生問題的位置裹虫,同時結(jié)合內(nèi)存分配釋放歷史和調(diào)用棧,可以發(fā)現(xiàn)問題融击。

至于上文提到的程序不會crash的原因筑公,其實(shí)有很多。

1.對象內(nèi)存釋放時尊浪,所用內(nèi)存并沒有完全被擦除匣屡,仍有舊對象部分?jǐn)?shù)據(jù)可用

2.原內(nèi)存位置被寫入同類或同樣結(jié)構(gòu)的數(shù)據(jù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拇涤,隨后出現(xiàn)的幾起案子捣作,更是在濱河造成了極大的恐慌,老刑警劉巖鹅士,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件券躁,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)也拜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門以舒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慢哈,你說我怎么就攤上這事蔓钟。” “怎么了岸军?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵奋刽,是天一觀的道長。 經(jīng)常有香客問我艰赞,道長佣谐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任方妖,我火速辦了婚禮狭魂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘党觅。我一直安慰自己雌澄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布杯瞻。 她就那樣靜靜地躺著镐牺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪魁莉。 梳的紋絲不亂的頭發(fā)上睬涧,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音旗唁,去河邊找鬼畦浓。 笑死,一個胖子當(dāng)著我的面吹牛检疫,可吹牛的內(nèi)容都是我干的讶请。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屎媳,長吁一口氣:“原來是場噩夢啊……” “哼夺溢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烛谊,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤风响,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晒来,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钞诡,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了荧降。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片接箫。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖朵诫,靈堂內(nèi)的尸體忽然破棺而出辛友,到底是詐尸還是另有隱情,我是刑警寧澤剪返,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布废累,位于F島的核電站,受9級特大地震影響脱盲,放射性物質(zhì)發(fā)生泄漏邑滨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一钱反、第九天 我趴在偏房一處隱蔽的房頂上張望掖看。 院中可真熱鬧,春花似錦面哥、人聲如沸哎壳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽归榕。三九已至,卻和暖如春吱涉,著一層夾襖步出監(jiān)牢的瞬間刹泄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工邑飒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留循签,地道東北人级乐。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓疙咸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親风科。 傳聞我的和親對象是個殘疾皇子撒轮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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