iOS的內(nèi)存分布探究

前言

最近遇到一些內(nèi)存相關(guān)crash攘烛,排查問題過程中產(chǎn)生對進(jìn)程內(nèi)整個(gè)地址空間分布的疑惑坟漱。搜查了一番資料靖秩,網(wǎng)上關(guān)于Linux進(jìn)程地址空間分布的介紹比較詳細(xì)竖瘾,但是iOS實(shí)際運(yùn)行效果的比較少捕传。
本文基于網(wǎng)上相關(guān)文章,進(jìn)行實(shí)際測試职辅,探究App實(shí)際運(yùn)行過程中的地址分布域携。

正文

32位的分布情況

32位的機(jī)器鱼喉,每個(gè)進(jìn)程會(huì)有4G虛擬地址空間趋观,較高的1G是從0xC0000000到0xFFFFFFFF的內(nèi)核空間(Kernel Space )皱坛,較低的3G是從0x00000000到0xBFFFFFFF用戶空間(User Space )剩辟。 內(nèi)核空間中存放的是內(nèi)核代碼和數(shù)據(jù)往扔,用戶空間中存放的是App進(jìn)程的代碼和數(shù)據(jù)萍膛。這里地址指的都是虛擬地址空間卦羡,由操作系統(tǒng)負(fù)責(zé)映射為物理地址绿饵。
把最常用的幾個(gè)概念堆瓶颠、棧粹淋、數(shù)據(jù)段、代碼段做一個(gè)地址從大到小的排序:

  • 棧:在函數(shù)調(diào)用過程中屋匕,每個(gè)函數(shù)都會(huì)有一個(gè)相關(guān)的區(qū)域來存儲(chǔ)函數(shù)的參數(shù)和局部變量过吻,每次進(jìn)行函數(shù)調(diào)用的時(shí)候系統(tǒng)都會(huì)往棧壓入一個(gè)新的棧幀纤虽,在函數(shù)返回時(shí)清除逼纸。入棧和出棧的操作非臣貌酰快菠发,這個(gè)過程會(huì)用到兩個(gè)寄存器:fp和sp寄存器雷酪。
  • 堆:在進(jìn)程運(yùn)行過程中哥力,用于存儲(chǔ)局部變量之外的變量吩跋。工作中常用的malloc函數(shù)渔工、new操作符等可以從堆中申請內(nèi)存。上面的棧很像數(shù)據(jù)結(jié)構(gòu)中的棧梁丘,但這里的堆并不像數(shù)據(jù)結(jié)構(gòu)的堆氛谜,其分配的方式是鏈表式区端,用brk()函數(shù)從操作系統(tǒng)批發(fā)內(nèi)存,再零售給用戶杨何。
  • 數(shù)據(jù)段:通常指的段和data段危虱,bss段內(nèi)是未被初始化的靜態(tài)變量槽地,data段是在代碼中已經(jīng)初始化的靜態(tài)變量捌蚊。data段變大會(huì)導(dǎo)致啟動(dòng)速度變慢近弟,bss段變大幾乎不影響。因?yàn)閎ss段只需要預(yù)留位置窗宦,并沒有真正的copy操作赴涵。相比data段增加的是具體的數(shù)據(jù),bss段增加的只是數(shù)據(jù)描述信息扇苞。
  • 代碼段:程序運(yùn)行的機(jī)器指令鳖敷,由代碼編譯產(chǎn)生定踱。

64位的實(shí)際分布

對于一個(gè)iOS開發(fā)來說崖媚,目前大部分手機(jī)都是64位機(jī)器至扰,還是需要對實(shí)際運(yùn)行結(jié)果進(jìn)行一些測試资锰。
以下真機(jī)測試的機(jī)型是iPhone XS Max + iOS 14.5绷杜。

64位機(jī)器鞭盟,進(jìn)程內(nèi)存地址從高到低分別是:
0xFFFF FFFF FFFF FFFF ??
內(nèi)核空間
用戶空間-保留區(qū)域
擴(kuò)展使用區(qū)域
系統(tǒng)共享庫
棾菟撸空間
內(nèi)存映射區(qū)域(mmap)
堆空間
BSS段
DATA段
Text段
0x0000 0000 0000 0000

常見概念-堆粤剧、棧抵恋、數(shù)據(jù)段弧关、代碼段

堆和棧

用一段簡單的代碼世囊,分別從堆和棧上面創(chuàng)建一塊內(nèi)存:

  char stack_address;
  UIView *heap_view_address = [[UIView alloc] init];
  NSLog(@"0x%016lx => stack 0x%016lx => heap", (long)&stack_address, (long)heap_view_address);

輸出 0x16f4c5af7 => stack 0x100e0d8a0 => heap株憾,可以大概知道棧和堆所在區(qū)域号胚,0x16F4...是棧地址的開始箱亿,0x100E...是堆地址的開始届惋。

數(shù)據(jù)段

bss段內(nèi)是未被初始化的靜態(tài)變量脑豹,data段是在代碼中已經(jīng)初始化的靜態(tài)變量衡查。

// 函數(shù)外-靜態(tài)變量
static int vcStaticInt = 1024;
static int vcStaticNotInit;

// 函數(shù)內(nèi)
NSLog(@"0x%lx => data 0x%lx => bss", (long)&vcStaticInt, (long)&vcStaticNotInit);

vcStaticNotInit代表bss段俱饿,最終的地址是0x100945788拍埠。
vcStaticInt代表data段枣购,最終的地址是0x1009455f8棉圈。

代碼段

代碼段是代碼編譯后的機(jī)器指令迄损,可以用一個(gè)類來定位:

NSLog(@"class_address: 0x%lx\n", (long)[ViewController class]);

最終輸出的class_address是0x100945500芹敌。

將這幾個(gè)地址的大小進(jìn)行排序,可以看到有:
0x16F4C 5AF7(棧地址)
0x100E0 D8A0(堆地址)
0x10094 5788(bss段)
0x10094 55F8(data段)
0x10094 5500(Text段)

系統(tǒng)共享庫

下面是兩個(gè)不同App(bundle id不一樣)在同手機(jī)上的運(yùn)行crash日志碧聪,對比可以發(fā)現(xiàn):在dyld之前的系統(tǒng)庫地址不一樣,在dyld之后的地址都是一樣的捆等。

App中存在很多系統(tǒng)動(dòng)態(tài)庫谒养,在啟動(dòng)時(shí)依賴dyld加載系統(tǒng)動(dòng)態(tài)庫到內(nèi)存中明郭。App依賴的具體系統(tǒng)動(dòng)態(tài)庫可能不同薯定,但是都是iOS系統(tǒng)提供的话侄。自然可以采用一種優(yōu)化App啟動(dòng)速度方法:將所有的的系統(tǒng)依賴庫按照固定的地址寫在某個(gè)固定區(qū)域年堆,這樣只需保證App運(yùn)行時(shí)這塊內(nèi)存不被使用,就能保證所有App啟動(dòng)時(shí)候不需要去裝載所有的動(dòng)態(tài)庫。

內(nèi)存映射區(qū)域

在棾空間的下方和堆空間的上方谊却,有一塊區(qū)域是內(nèi)存映射區(qū)域炎辨。系統(tǒng)可以將文件的內(nèi)容直接映射到內(nèi)存碴萧,App可以通過mmap()方法請求將磁盤上文件的地址信息與進(jìn)程用的虛擬邏輯地址進(jìn)行映射乙嘀。相比普通的讀寫文件,當(dāng)App讀取一個(gè)文件時(shí)有兩步:先將文件從磁盤讀取到物理內(nèi)存破喻,再從內(nèi)核空間拷貝到用戶空間虎谢。內(nèi)存映射則可以減少操作系統(tǒng)的地址轉(zhuǎn)換帶來的消耗。

可以寫一段mmap的代碼來觀察生成的地址

- (void)testMmap {
  NSString *imagePathStr = [[NSBundle mainBundle] pathForResource:@"abc" ofType:@"png"];
  size_t dataLength;
  void *dataPtr;
  // MapFile是自己寫的mmap方法
  int errorCode = MapFile([imagePathStr cStringUsingEncoding:NSUTF8StringEncoding], &dataPtr, &dataLength);
  NSLog(@"mmapData:0x%lx, bytes_address:0x%lx, size:%d, error:%d", (long)dataPtr, (long)dataPtr, (long)dataLength, errorCode);
}

最終輸出的dataLength地址是0x1026b8000曹质,size是18432婴噩,注意到這個(gè)地址是在上面的堆和棧之間。

用戶空間-保留區(qū)域

這一塊沒有查到相關(guān)信息羽德,如有資料求分享几莽。以下是實(shí)際運(yùn)行的分析。

@interface TestOCObject : NSObject
@property (nonatomic, readonly, assign) char *name_buffer;
@end
@implementation TestOCObject {
  char name[102400];
}
- (char *)name_buffer {
  return name;
}
@end

- (void)testHeapSize:(int)count {
  NSMutableArray<TestOCObject *> *arr = [NSMutableArray new];
  while (true) {
    char stackSize;
    TestOCObject *obj = [[TestOCObject alloc] init];
    ++count;
    if (obj) {
      NSLog(@"%05d stack_address => 0x%lx heap_address => 0x%lx chars => 0x%lx", count, (long)&stackSize, (long)obj, (long)obj.name_buffer);
      [arr addObject:obj];
    }
    else {
      break;
    }
  }
}

當(dāng)進(jìn)程不斷從堆空間申請內(nèi)存章蚣,剛開始的時(shí)候從堆空間分配的地址是小于棧空間地址洒忧,但是隨著內(nèi)存不斷被使用,在14700次左右的時(shí)候蛉抓,堆空間分配的地址就會(huì)超過棧空間的地址笑跛。

14703 stack_address => 0x16d751aef heap_address => 0x16d630000
14704 stack_address => 0x16d751aef heap_address => 0x16db28000

然后在17000次左右的時(shí)候,出現(xiàn)了一次大的地址變動(dòng):從0x1變成了0x2a開始陈哑。0x2a的地址空間是在系統(tǒng)共享庫地址(0x1a)上方。

之所以有這樣的現(xiàn)象,個(gè)人理解是為了兼容32位的情況。因?yàn)椴还苁窍到y(tǒng)共享庫族铆,還是堆、棧地址空間的大小逝淹,初始地址都是在32位的地址空間內(nèi)。而后面地址從0x2a0000000開始,就已經(jīng)超過了32位的地址空間熊咽,屬于64位機(jī)器的地址空間。最終運(yùn)行到達(dá)到63000次左右衫仑,一次是100KB航徙,可以計(jì)算得到63000*100KB/1024/1024=6G左右的空間杠袱。

這時(shí)候產(chǎn)生了一個(gè)疑問:為什么32位的情況下,堆空間只有1G多空間大形坪?為什么64位的情況下兼犯,堆空間也只有6G多空間大形诚肌险领?(可以先暫停閱讀,思考后見最下面分析)

思維發(fā)散

經(jīng)過上面的分析脐湾,再來解析一下以前的問題:

普通對象和靜態(tài)變量有哪些區(qū)別鹰霍?

對象存儲(chǔ)區(qū)域不同孟岛,普通對象一般是在棧、堆上荧恍,但是靜態(tài)變量會(huì)存儲(chǔ)在數(shù)據(jù)段雌芽,地址會(huì)有較大的差別。

對象實(shí)例和對象方法的關(guān)系?

一個(gè)OC對象的實(shí)例,其實(shí)就是一塊存儲(chǔ)數(shù)據(jù)的內(nèi)存。內(nèi)存中有指針跃须,可以指向?qū)ο蟮念惖刂罚ùa段)投储;訪問一個(gè)對象方法其實(shí)是通過內(nèi)存中的指針找到類地址勋眯,然后將對象的內(nèi)存地址和調(diào)用的方法名作為參數(shù)傳遞志秃。也可以用一種形象但可能不太恰當(dāng)?shù)谋扔鳎簣?zhí)行一個(gè)方法就像帶著原料跑到加工廠進(jìn)行流水線的處理钧舌,原料就是對象的內(nèi)存地址和其他傳入方法的內(nèi)存地址,流水線編譯生成的固定機(jī)器指令。

椢荼耄空間地址從高到低增長蟹但?

前面已經(jīng)提到口糕,在函數(shù)調(diào)用過程中,會(huì)往棧壓入一個(gè)新的棧幀,在函數(shù)返回時(shí)清除再扭。
那么只需要構(gòu)造一個(gè)遞歸調(diào)用泛范,觀察每個(gè)函數(shù)局部變量的地址即可觀察到椙裕空間的地址變化:

- (void)testStackSize:(int)count {
  char stackSize[1024];
  NSLog(@"%05d stack_address => 0x%lx ", count, (long)&stackSize);
  if (count < 1000) {
    ++count;
    [self testStackSize:count];
  }
  else {
    NSLog(@"end");
  }

需要注意骡送,同一個(gè)函數(shù)內(nèi)昌渤,先后申請兩個(gè)局部變量A和B潜支,觀察A和B的地址裁替,并不能看出椬锻铮空間的地址變化。因?yàn)橥粋€(gè)函數(shù)內(nèi)的局部變量可能會(huì)受到編譯器的優(yōu)化,導(dǎo)致不符合預(yù)期。所以觀察不同棧幀間的局部變量地址變化更為準(zhǔn)確粮彤。
通過上面的代碼可以知道,棾揪澹空間地址確實(shí)是從高到低增長贰逾,隨著遞歸函數(shù)的不斷調(diào)用言缤,局部變量的地址也在不斷變小哮独。在真機(jī)測試的情況下悴务,兩次運(yùn)行的stackSize分別為 0x16ce86868和0x16ce86408别洪,地址差為0x000000460痢毒, 轉(zhuǎn)換成二進(jìn)制4(16^2)+616=1024+96凭舶, 其中1024是申請的char數(shù)組义屏,96則是函數(shù)遞歸調(diào)用的其他開銷兄墅。這段遞歸代碼運(yùn)行994次會(huì)報(bào)錯(cuò),由此可以計(jì)算主線程的棧空間有1MB左右。(此部分為實(shí)際運(yùn)行效果推算,不同環(huán)境下可能結(jié)果各異)

堆空間地址從低到高增長灌具?

堆空間的內(nèi)存分配方式與棧空間不同,如果先后從堆上創(chuàng)建兩個(gè)對象A和B,再對比兩個(gè)對象的內(nèi)存地址帖努,那么A和B的大小應(yīng)該沒有直接關(guān)系匙监。因?yàn)槎芽臻g存在對象的創(chuàng)建和銷毀,當(dāng)對象A和B創(chuàng)建時(shí),都有可能用到前面某些對象銷毀時(shí)被回收的內(nèi)存地址击儡。
常說的堆空間地址從低到高增長鸽疾,是Linux系統(tǒng)堆空間初始分配之后,擴(kuò)大堆空間大小的時(shí)候款慨,會(huì)往高地址增長圣猎。iOS實(shí)際運(yùn)行過程中,有可能先申請到一個(gè)很大的內(nèi)存地址,比如說下面這代碼:

NSObject *oc_object = [[NSObject alloc] init];
TestOCObject *oc_big_object = [[TestOCObject alloc] init];
NSLog(@"oc_object_address => 0x%lx oc_big_object_address => 0x%lx", (long)oc_object, (long)oc_big_object);

TestOCObject是上文用到一個(gè)自定義OC類岸蜗,當(dāng)代碼實(shí)際運(yùn)行的時(shí)候,可以會(huì)看到輸出
oc_object_address => 0x283d84cb0 oc_big_object_address => 0x1026b8000
其中oc_object的地址是0x283d84cb0蛇损,而oc_big_object的地址是0x1026b8000
0x28開頭的地址也會(huì)被用于分配內(nèi)存,一般用于內(nèi)存較小的情況岩灭,而內(nèi)存比較大的時(shí)候仍然會(huì)從正常的堆地址空間開始泡孩。(這個(gè)不同地址取決于libsystem_malloc.dylib對申請內(nèi)存大小的不同處理)

為什么32位的情況下,堆空間只有1G多空間大刑芤邸巩梢?為什么64位的情況下,堆空間也只有6G多空間大欣业狻募谎?

操作系統(tǒng)內(nèi)存是段頁式管理,App先分段再分頁,頁是內(nèi)存管理的基本單位缭黔。(32位是4096B=4KB,64位是16KB)
當(dāng)App訪問虛擬內(nèi)存時(shí)管宵,操作系統(tǒng)會(huì)檢查虛擬內(nèi)存對應(yīng)物理內(nèi)存是否存在荚斯,如果不存在則觸發(fā)一次缺頁中斷(Page Fault),將數(shù)據(jù)從磁盤加載到物理內(nèi)存中称鳞,并建立物理內(nèi)存和虛擬內(nèi)存的映射慌盯。
32位機(jī)器的虛擬空間最多只有4G,其中1G還要留給內(nèi)核空間,堆和棧之間能留下來的空間并不寬裕与斤,即使加上椑保空間到系統(tǒng)共享庫之間的區(qū)域移盆,總共也只有1G多空間蚁署。而64位的機(jī)器用于充足的虛擬地址空間,虛擬內(nèi)存占用超過1G多之后蜕乡,會(huì)從0x2a開始申請?zhí)摂M地址父虑。但是由于有物理內(nèi)存的限制,過大的虛擬內(nèi)存占用會(huì)導(dǎo)致物理內(nèi)存快速消耗奋单,當(dāng)物理內(nèi)存被消耗完成后猫十,就需要釋放現(xiàn)有的內(nèi)存頁乏苦。所以App并不需要有非常大的虛擬內(nèi)存,因?yàn)槠款i往往出現(xiàn)在物理內(nèi)存上面繁疤。
另外這里為什么可以創(chuàng)建6G的虛擬內(nèi)存架忌,這是因?yàn)闇y試代碼申請的內(nèi)存頁大都沒有寫入操作,當(dāng)內(nèi)存有壓力的時(shí)候吱七,會(huì)被系統(tǒng)進(jìn)行壓縮成Compressed Memory鹤竭。如果增加一個(gè)簡單的寫入操作踊餐,那么這個(gè)內(nèi)存頁就變成了臟內(nèi)存,進(jìn)程在1G多占用的時(shí)候就會(huì)被操作系統(tǒng)kill臀稚。

- (void)testHeapSize:(int)count {
  NSMutableArray<TestOCObject *> *arr = [NSMutableArray new];
  while (true) {
    char stackSize;
    TestOCObject *obj = [[TestOCObject alloc] init];
    ++count;
    if (obj) {
      NSLog(@"%05d stack_address => 0x%lx heap_address => 0x%lx chars => 0x%lx", count, (long)&stackSize, (long)obj, (long)obj.name_buffer);
      // 增加write操作
      for (int i = 0; i < 100; ++i) {
        memcpy(obj.name_buffer + (i * 1024), "hello", 6);
      }
      [arr addObject:obj];
    }
    else {
      break;
    }
  }
}

輔助工具

objdump指令可以得到二進(jìn)制分布吝岭,比如說下面的objdump -d LearnMemoryAddress

總結(jié)

本文為實(shí)際運(yùn)行結(jié)果的分析,測試機(jī)型-iPhone XS Max + iOS 14.5吧寺。
實(shí)際運(yùn)行結(jié)果的解析部分可能存在錯(cuò)誤窜管,如果發(fā)現(xiàn)請幫忙糾正。
知道各個(gè)地址空間的分布稚机,能幫助我們更好理解iOS系統(tǒng)幕帆。在面對內(nèi)存相關(guān)crash的時(shí)候,看到地址就能大概判斷是屬于哪一個(gè)區(qū)域赖条,也能更加清晰具體去解析錯(cuò)誤失乾。

參考資料-Memory Usage Performance Guidelines

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纬乍,隨后出現(xiàn)的幾起案子碱茁,更是在濱河造成了極大的恐慌,老刑警劉巖仿贬,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纽竣,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蜓氨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門聋袋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人语盈,你說我怎么就攤上這事舱馅$峙荩” “怎么了刀荒?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長棘钞。 經(jīng)常有香客問我缠借,道長,這世上最難降的妖魔是什么宜猜? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任泼返,我火速辦了婚禮,結(jié)果婚禮上姨拥,老公的妹妹穿的比我還像新娘绅喉。我一直安慰自己,他們只是感情好叫乌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布柴罐。 她就那樣靜靜地躺著,像睡著了一般憨奸。 火紅的嫁衣襯著肌膚如雪革屠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天排宰,我揣著相機(jī)與錄音似芝,去河邊找鬼。 笑死板甘,一個(gè)胖子當(dāng)著我的面吹牛党瓮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盐类,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼麻诀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傲醉?” 一聲冷哼從身側(cè)響起蝇闭,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎硬毕,沒想到半個(gè)月后呻引,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吐咳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年逻悠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了元践。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡童谒,死狀恐怖单旁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饥伊,我是刑警寧澤象浑,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站琅豆,受9級(jí)特大地震影響愉豺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜茫因,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一蚪拦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冻押,春花似錦驰贷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狼渊,卻和暖如春箱熬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狈邑。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工城须, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人米苹。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓糕伐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蘸嘶。 傳聞我的和親對象是個(gè)殘疾皇子良瞧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

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

  • 在iOS中,內(nèi)存主要分為棧區(qū)训唱、堆區(qū)褥蚯、全局區(qū)、常量區(qū)况增、代碼區(qū)五大區(qū)域赞庶。如下圖所示 下面分別介紹這五大區(qū) 棧區(qū)(Sta...
    輝輝歲月閱讀 950評論 0 1
  • 前言: 在iOS開發(fā)中,平常大家都會(huì)說,堆區(qū)歧强,棧區(qū)澜薄,都是存在虛擬內(nèi)存。 虛擬內(nèi)存五大區(qū):堆區(qū)摊册、棧區(qū)肤京、全局區(qū)、常量區(qū)...
    淺墨入畫閱讀 502評論 0 2
  • iOS內(nèi)存問題: IBOutlet為啥是weak的茅特?因?yàn)閟ubview添加到view上時(shí)忘分,view會(huì)“擁有”sub...
    davidxwwang閱讀 1,528評論 0 1
  • iOS中,內(nèi)存主要分為棧區(qū)温治、堆區(qū)饭庞、全局區(qū)戒悠、常量區(qū)熬荆、代碼區(qū)五大區(qū)域 1. 棧區(qū) 定義 棧是系統(tǒng)數(shù)據(jù)結(jié)構(gòu),其對應(yīng)的進(jìn)程...
    北京_小海閱讀 2,620評論 0 6
  • 程序進(jìn)程是不能直接訪問物理內(nèi)存的绸狐,系統(tǒng)通過虛擬內(nèi)存方式管理進(jìn)程內(nèi)存卤恳。 圖片來源 《深入理解計(jì)算機(jī)系統(tǒng)》8.2.3 ...
    wenfh2020閱讀 1,115評論 0 0