探索iOS數(shù)組容器的存儲結(jié)構(gòu)

在C++中我們我們通常使用順序存儲作為數(shù)組的存儲結(jié)構(gòu), 那在OC中, 封裝過的NSArray和NSMutableArray到底是順序存儲還是鏈式存儲的呢, 今天就來一探究竟.

上代碼

    NSString *str = @"11";
    NSLog(@"%p", str);
    NSArray *array = @[str, @"1", @"2"];
    NSLog(@"array:%p", array);

這里用NSArray數(shù)組存放3個元素, 第一個元素是@"11"這個字符串, 我們知道, 字符串是作為常量的, 地址是不會改變的, 并且, 數(shù)組的首地址就是str的地址, 因此我們打印出str的地址.

控制臺輸出如下

0x104f5d078

然后我們在NSLog(@"array:%p", array);這一行下斷點, 并打印當前的內(nèi)存情況

命令 (lldb) x/100xb array

控制臺輸出如下

0x60000024b1c0: 0xc0 0xda 0x1c 0x06 0x01 0x00 0x00 0x00
0x60000024b1c8: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b1d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b1d8: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b1e0: 0xe0 0x94 0x22 0x00 0x00 0x60 0x00 0x00
0x60000024b1e8: 0x60 0xad 0x03 0x00 0x00 0x60 0x00 0x00
0x60000024b1f0: 0xad 0xbe 0xb7 0x66 0x89 0xf7 0xdd 0xba
0x60000024b1f8: 0x80 0xaf 0x24 0x00 0x00 0x60 0x00 0x00
0x60000024b200: 0xc0 0x79 0x22 0x00 0x00 0x60 0x00 0x00
0x60000024b208: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b210: 0x61 0x63 0x74 0x69 0x6f 0x6e 0x00 0x00
0x60000024b218: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b220: 0xd0 0xb0 0x24 0x00

這里的內(nèi)存主要打印的是NSArray這個"結(jié)構(gòu)體"(所有的OC對象實際都是結(jié)構(gòu)體)在內(nèi)存上的存儲情況.

0x60000024b1c8: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00

這一行0x03我們猜想是數(shù)組的長度, 感興趣的小伙伴可以換下數(shù)組, 發(fā)現(xiàn)這里確實是數(shù)組的長度, 那數(shù)組里面的真實的數(shù)據(jù)在哪里呢?
首先這些真實數(shù)據(jù)的首地址一定在NSArray這個"結(jié)構(gòu)體"里面有存儲, 也就是x/100xb array對應(yīng)的控制臺輸出一定有一行表示這個地址.由于從左往右是從低到高, 看下哪些可能像地址, 目標定位到0x60000024b1e00x60000024b1e8這兩行, 先打印0x60000024b1e0的內(nèi)存

命令 (lldb) x/100xb 0x6000002294e0

控制臺輸出如下

0x6000002294e0: 0x78 0xd0 0xf5 0x04 0x01 0x00 0x00 0x00
0x6000002294e8: 0xb8 0xd0 0xf5 0x04 0x01 0x00 0x00 0x00
0x6000002294f0: 0xd8 0xd0 0xf5 0x04 0x01 0x00 0x00 0x00
0x6000002294f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000229500: 0xad 0xbe 0xb7 0x66 0x89 0xf7 0xdd 0xba
0x600000229508: 0xc0 0x93 0x22 0x00 0x00 0x60 0x00 0x00
0x600000229510: 0x0c 0x53 0x77 0x69 0x73 0x73 0x20 0x47
0x600000229518: 0x65 0x72 0x6d 0x61 0x6e 0x00 0x00 0x00
0x600000229520: 0x18 0xe2 0x1c 0x06 0x01 0x00 0x00 0x00
0x600000229528: 0x8c 0x07 0x00 0x00 0x01 0x00 0x00 0x00
0x600000229530: 0x0c 0x47 0x72 0x6f 0x75 0x70 0x2d 0x4e
0x600000229538: 0x6f 0x72 0x64 0x69 0x63 0x00 0x00 0x00
0x600000229540: 0x18 0xe2 0x1c 0x06

看這里的第一行內(nèi)存里的數(shù)據(jù)是0x0104f5d078, 這個數(shù)據(jù)剛好就是str的地址, 因此我們先假0x6000002294e0就是數(shù)組對應(yīng)的真實數(shù)據(jù)的首地址, 然后分別打印這些對象的真實數(shù)據(jù)

命令 (lldb)po 0x0104f5d078
11
(lldb) po 0x0104f5d0b8
1
(lldb) po 0x0104f5d0d8
2
真的是數(shù)組里面的數(shù)據(jù), 再看下存儲這些對象的內(nèi)存地址

0x6000002294e0
0x6000002294e8
0x6000002294f0

剛好都差8個字節(jié), 我們知道OC里面的數(shù)組存儲的是對象類型, 也就是指針, 指針在64位系統(tǒng)上是8個字節(jié), 這就印證了我們的一個假設(shè)NSArray在內(nèi)存上是連續(xù)存儲的.
為了進一步研究, 我們打印剛才NSArray"結(jié)構(gòu)體"中另一個可疑的首地址的內(nèi)存情況0x60000024b1e8

(lldb) x/100xb 0x60000024b1e8
0x60000024b1e8: 0x60 0xad 0x03 0x00 0x00 0x60 0x00 0x00
0x60000024b1f0: 0xad 0xbe 0xb7 0x66 0x89 0xf7 0xdd 0xba
0x60000024b1f8: 0x80 0xaf 0x24 0x00 0x00 0x60 0x00 0x00
0x60000024b200: 0xc0 0x79 0x22 0x00 0x00 0x60 0x00 0x00
0x60000024b208: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b210: 0x61 0x63 0x74 0x69 0x6f 0x6e 0x00 0x00
0x60000024b218: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60000024b220: 0xd0 0xb0 0x24 0x00 0x00 0x60 0x00 0x00
0x60000024b228: 0x20 0xbe 0x23 0x00 0x80 0x60 0x00 0x00
0x60000024b230: 0x55 0xe6 0xf6 0x55 0x35 0x05 0x00 0xa0
0x60000024b238: 0x40 0xd7 0x09 0x00 0x00 0x60 0x00 0x00
0x60000024b240: 0xa0 0x0a 0x28 0x00 0x80 0x60 0x00 0x00
0x60000024b248: 0xf0 0x0a 0x28 0x00

嘗試打印里面的數(shù)據(jù)

(lldb) po 0x60000003ad60
105553116507488

0x60000003ad60好像做不起首地址.

下面研究下NSMutableArray的存儲情況, 根據(jù)NSArray是順序存儲這個事實, 我們假設(shè)NSMutableArray也是順序存儲的. 大膽假設(shè)還需小心求證.

上代碼

    NSString *str = @"11";
    NSLog(@"%p", str);
    NSMutableArray *arrayM = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
        [arrayM addObject:str];
    }
    NSLog(@"arrayM:%p", arrayM);

這里NSMutableArrayNSArray不同的地方就是NSMutableArray可能需要擴容

看初始化的內(nèi)存情況

(lldb) x/100xb arrayM
0x600000278b40: 0x98 0x3a 0xde 0x04 0x01 0x00 0x00 0x00
0x600000278b48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b68: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b70: 0x40 0x38 0x22 0x00 0x00 0x60 0x00 0x00
0x600000278b78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b80: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x600000278b88: 0x80 0x84 0x27 0x00 0x00 0x60 0x00 0x00
0x600000278b90: 0x80 0xf0 0x25 0x00 0x00 0x60 0x00 0x00
0x600000278b98: 0x00 0x00 0x00 0x00 0x73 0x42 0x61 0x72
0x600000278ba0: 0x70 0x72 0x6f 0x63

0x40 0x38 0x22 0x00 0x00 0x60 可能存的是首地址吧, who care, 執(zhí)行完一次[arrayM addObject:str];后的內(nèi)存

(lldb) x/100xb arrayM
0x600000278b40: 0x98 0x3a 0xde 0x04 0x01 0x00 0x00 0x00
0x600000278b48: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b58: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b60: 0xa0 0xaa 0x01 0x00 0x80 0x60 0x00 0x00
0x600000278b68: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b70: 0x40 0x38 0x22 0x00 0x00 0x60 0x00 0x00
0x600000278b78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b80: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x600000278b88: 0x80 0x84 0x27 0x00 0x00 0x60 0x00 0x00
0x600000278b90: 0x80 0xf0 0x25 0x00 0x00 0x60 0x00 0x00
0x600000278b98: 0x00 0x00 0x00 0x00 0x73 0x42 0x61 0x72
0x600000278ba0: 0x70 0x72 0x6f 0x63

繼續(xù)看可疑的首地址

(lldb) x/100xb 0x60800001aaa0
0x60800001aaa0: 0x78 0xb0 0x69 0x03 0x01 0x00 0x00 0x00
0x60800001aaa8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60800001aab0: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x60800001aab8: 0x70 0xaa 0x01 0x00 0x80 0x60 0x00 0x00
0x60800001aac0: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x60800001aac8: 0xa0 0xab 0x01 0x00 0x80 0x60 0x00 0x00
0x60800001aad0: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x60800001aad8: 0x10 0xaa 0x01 0x00 0x80 0x60 0x00 0x00
0x60800001aae0: 0x00 0xaa 0x81 0x41 0xe2 0x7f 0x00 0x00
0x60800001aae8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x60800001aaf0: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x60800001aaf8: 0xb0 0xaa 0x01 0x00 0x80 0x60 0x00 0x00
0x60800001ab00: 0xd8 0x45 0xde 0x04
(lldb) po 0x010369b078
11

果然11進來了
再看執(zhí)行了2次add后的內(nèi)存

(lldb) x/100xb arrayM
0x600000278b40: 0x98 0x3a 0xde 0x04 0x01 0x00 0x00 0x00
0x600000278b48: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b58: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b60: 0x20 0x38 0x22 0x00 0x00 0x60 0x00 0x00
0x600000278b68: 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b70: 0x40 0x38 0x22 0x00 0x00 0x60 0x00 0x00
0x600000278b78: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000278b80: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x600000278b88: 0x80 0x84 0x27 0x00 0x00 0x60 0x00 0x00
0x600000278b90: 0x80 0xf0 0x25 0x00 0x00 0x60 0x00 0x00
0x600000278b98: 0x00 0x00 0x00 0x00 0x73 0x42 0x61 0x72
0x600000278ba0: 0x70 0x72 0x6f 0x63

首地址變成了0x20 0x38 0x22 0x00 0x00 0x60, 這是由于擴容導(dǎo)致的

(lldb) x/100xb 0x600000223820
0x600000223820: 0x78 0xb0 0x69 0x03 0x01 0x00 0x00 0x00
0x600000223828: 0x78 0xb0 0x69 0x03 0x01 0x00 0x00 0x00
0x600000223830: 0x78 0xb0 0x69 0x03 0x01 0x00 0x00 0x00
0x600000223838: 0x78 0xb0 0x69 0x03 0x01 0x00 0x00 0x00
0x600000223840: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000223848: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000223850: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000223858: 0xa8 0x70 0xde 0x04 0x01 0x00 0x00 0x00
0x600000223860: 0xad 0xbe 0x4c 0xac 0xb5 0x25 0xdd 0xba
0x600000223868: 0xa0 0x3a 0x22 0x00 0x00 0x60 0x00 0x00
0x600000223870: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000223878: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000223880: 0xb0 0xed 0x25 0x00

還是順序存儲的. 有興趣的小伙伴可以繼續(xù)看下執(zhí)行完10次add后的情況, 結(jié)論是:還是順序存儲的, 不過首地址會經(jīng)常變.

綜上NSArrayNSMutableArray在內(nèi)存上都是順序存儲的, 這可能和我之前想的NSMutableArray是鏈式存儲的說法有些出入, 要深入研究才能知道真實情況和我們想的有什么區(qū)別. 精通iOS, 從lldb開始.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末覆旭,一起剝皮案震驚了整個濱河市稚伍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌博投,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橘洞,死亡現(xiàn)場離奇詭異,居然都是意外死亡汁展,警方通過查閱死者的電腦和手機私蕾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門僵缺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人踩叭,你說我怎么就攤上這事磕潮〕诿” “怎么了们童?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铲汪。 經(jīng)常有香客問我斤富,道長膏潮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任满力,我火速辦了婚禮焕参,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脚囊。我一直安慰自己龟糕,他們只是感情好桐磁,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布悔耘。 她就那樣靜靜地躺著,像睡著了一般我擂。 火紅的嫁衣襯著肌膚如雪衬以。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天校摩,我揣著相機與錄音看峻,去河邊找鬼。 笑死衙吩,一個胖子當著我的面吹牛互妓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坤塞,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼冯勉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摹芙?” 一聲冷哼從身側(cè)響起灼狰,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浮禾,沒想到半個月后交胚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體份汗,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年蝴簇,在試婚紗的時候發(fā)現(xiàn)自己被綠了杯活。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡军熏,死狀恐怖轩猩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荡澎,我是刑警寧澤均践,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站摩幔,受9級特大地震影響彤委,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜或衡,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一焦影、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧封断,春花似錦斯辰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柄瑰,卻和暖如春闸氮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背教沾。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工蒲跨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人授翻。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓或悲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親堪唐。 傳聞我的和親對象是個殘疾皇子巡语,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

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

  • __block和__weak修飾符的區(qū)別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,284評論 0 6
  • 多線程羔杨、特別是NSOperation 和 GCD 的內(nèi)部原理捌臊。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,004評論 0 12
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 1,962評論 0 7
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,345評論 0 35
  • 今天用react開發(fā)兜材,準備引入一個組件本來是import Log from Log/index但是我卻寫成了 im...
    鄒小鄒大廚閱讀 283評論 0 0