iOS-Swift-匯編分析String、Array底層

一. 匯編分析String底層

iOS程序的內(nèi)存布局

Mach-O文件是iOS的可執(zhí)行文件,我們平時(shí)寫(xiě)的代碼都在Mach-O,所以我們窺探Mach-O文件喜喂,就相當(dāng)于窺探內(nèi)存了(因?yàn)镸ach-O文件載入內(nèi)存不會(huì)有太大變化瓤摧,只不過(guò)內(nèi)存是動(dòng)態(tài)更新的),如下圖:

從編碼到啟動(dòng)APP

問(wèn)題1

1個(gè)String變量占用多少內(nèi)存玉吁?
下面2個(gè)String變量照弥,底層存儲(chǔ)有什么不同?

var str1 = "0123456789" 
var str2 = "0123456789ABCDEF"

運(yùn)行如下代碼:

var str1 = "0123456789ABCDE"
print(MemoryLayout.stride(ofValue: str1)) //16 實(shí)際分配16字節(jié)
print(Mems.memStr(ofVal: &str1))

打咏薄:

16
0x3736353433323130 0xef45444342413938

通過(guò)打印可知:
16:str1實(shí)際分配16字節(jié)这揣,
0x3736353433323130 0xef45444342413938 :這是打印str1指針指向內(nèi)存存儲(chǔ)的東西,0x代表16進(jìn)制影斑,e代表直接把字符內(nèi)容存儲(chǔ)到內(nèi)存中给赞,f代表長(zhǎng)度15,通過(guò)查詢(xún)ASCII表可知0代表30矫户,1代表31......等等

總結(jié):
當(dāng)字符串長(zhǎng)度小于等于15片迅,1個(gè)字節(jié)留著存放長(zhǎng)度,另外15字節(jié)直接存放字符串的ASCII值皆辽,類(lèi)似于OC的tagger pointer技術(shù)

如果字符串再多一位呢柑蛇?

var str2 = "0123456789ABCDEF"
print(MemoryLayout.stride(ofValue: str2)) //16 實(shí)際分配16
print(Mems.memStr(ofVal: &str2))

打印:

16
0xd000000000000010 0x800000010000a790

可以發(fā)現(xiàn)驱闷,當(dāng)字符串長(zhǎng)度大于15耻台,就不是直接存儲(chǔ)字符串的值了

MJ老師通過(guò)窺探匯編得出如下結(jié)果,對(duì)于0xd000000000000010 0x800000010000a790:

  1. 前8字節(jié)存放的是字符創(chuàng)的長(zhǎng)度10空另,在16進(jìn)制中就是16
  2. 后8個(gè)字節(jié)存放的是:0x800000010000a790 = 字符串的真實(shí)地址 + 0x7fffffffffffffe0盆耽,所以字符串的真實(shí)地址 = 0x800000010000a790 - 0x7fffffffffffffe0(小技巧:字符串的真實(shí)地址 = 0x000000010000a790 + 0x20)

通過(guò)計(jì)算得出0x10000A7B0是"0123456789ABCDEF"的真實(shí)地址,讀取這個(gè)地址的內(nèi)存扼菠,如下:

x 0x10000a7b0: 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46   0123456789ABCDEF

可以發(fā)現(xiàn)摄杂,這個(gè)內(nèi)存地址存儲(chǔ)的的確是str2字符串。

  • 使用MachoView

那個(gè)這個(gè)地址:0x10000A7B0在哪呢娇豫?
這就要用到文章開(kāi)頭的知識(shí)了匙姜,我們窺探Mach-O文件畅厢,就相當(dāng)于窺探內(nèi)存冯痢,在Mach-O文件中我們可以知道0x10000A7B0地址存放在哪里

補(bǔ)充:
0x100000000: VM Address 虛擬地址
0x10000A7B0 = 0x100000000 + 0xA7B0
0xA7B0是Mach文件的地址,所以我們?cè)贛ach-O文件中找0xA7800就好了

運(yùn)行程序框杜,使用MachoView打開(kāi)程序的可執(zhí)行文件浦楣,可以發(fā)現(xiàn)0xA7B0放在常量區(qū),如下:

Mach-O文件.png

總結(jié):
字符串長(zhǎng)度 <= 0xF(15)咪辱,字符串內(nèi)容直接存放在str1變量的內(nèi)存中(比如:var str1 = "0123456789")
字符串長(zhǎng)度 > 0xF(15)振劳,字符串內(nèi)容存放在__TEXT.cstring中(常量區(qū)
字符串的地址值信息存放在str2變量的后8個(gè)字節(jié)中(比如:var str2 = "0123456789ABCDEFGHIJ")

問(wèn)題2

如果對(duì)String進(jìn)行拼接操作,String變量的存儲(chǔ)會(huì)發(fā)生什么變化油狂?

var str1 = "0123456789" 
var str2 = "0123456789ABCDEF"
str1.append("ABCDE") 
str1.append("F")
str2.append("G")

運(yùn)行如下代碼:

var str1 = "01234567"
print(Mems.memStr(ofVal: &str1))
str1.append("GIHJ")
print(Mems.memStr(ofVal: &str1))

打永帧:

0x3736353433323130 0xe800000000000000
0x3736353433323130 0xec0000004a484947

可以發(fā)現(xiàn)寸癌,當(dāng)字符串進(jìn)行拼接的時(shí)候,如果拼接后字符串長(zhǎng)度還是小于等于15弱贼,那么拼接的字符串還會(huì)放在原來(lái)的后面

如果字符串長(zhǎng)度本來(lái)是16蒸苇,拼接后大于16呢?

var str2 = "0123456789ABCDEF"
print(Mems.memStr(ofVal: &str2))
str2.append("G")
print(Mems.memStr(ofVal: &str2))

打铀甭谩:

0xd000000000000010 0x8000000100006620  //16字節(jié)溪烤,放常量區(qū)
0xf000000000000011 0x000000010068af60  //大于16字節(jié),放堆空間

根據(jù)上面的小技巧庇勃,0x000000010068af60 + 0x20得到字符串的真實(shí)地址:0x000000010068af80檬嘀,查看真實(shí)地址內(nèi)存,發(fā)現(xiàn)存儲(chǔ)的的確是上面的字符串

(lldb) x 0x000000010068af80
0x10068af80: 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46  0123456789ABCDEF
0x10068af90: 47 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  G...............
(lldb)

如何證明上面str2.append("G")之后是存放在堆空間责嚷?
很簡(jiǎn)單鸳兽,在malloc函數(shù)打個(gè)斷點(diǎn),如果走malloc函數(shù)罕拂,就說(shuō)明在堆空間
MJ老師在匯編里面在malloc函數(shù)打個(gè)斷點(diǎn)贸铜,執(zhí)行str2.append("G")發(fā)現(xiàn)的確走了malloc,說(shuō)明str2.append("G")之后是存放在堆空間

大總結(jié):

現(xiàn)在可以回答開(kāi)頭兩個(gè)問(wèn)題了

var str1 = "0123456789"
字符串長(zhǎng)度 <= 0xF(15)聂受,字符串內(nèi)容直接存放在str1變量的內(nèi)存中

var str2 = "0123456789ABCDEF"
字符串長(zhǎng)度 > 0xF(15)蒿秦,字符串內(nèi)容存放在__TEXT.cstring中(常量區(qū))
字符串的地址值信息存放在str2變量的后8個(gè)字節(jié)中

str1.append("ABCDE")
由于字符串長(zhǎng)度 <= 0xF,所以字符串內(nèi)容依然存放在str1變量的內(nèi)存中

str1.append("F")
開(kāi)辟堆空間
可能你會(huì)疑問(wèn)這里為什么是開(kāi)辟堆空間蛋济?
拼接之前str1是0123456789ABCDE棍鳖,這時(shí)候是字符串15字節(jié)+1字節(jié)(存放長(zhǎng)度),16個(gè)字節(jié)已經(jīng)滿(mǎn)了碗旅,所以無(wú)法拼接渡处。
那么放常量區(qū)呢?更不可以祟辟,因?yàn)槌A繀^(qū)的內(nèi)容不可以改医瘫,所以只能開(kāi)辟堆空間。

str2.append("G")
開(kāi)辟堆空間

二. 匯編分析Array底層

關(guān)于Array的思考

public struct Array<Element> 
var arr = [1, 2, 3, 4]

1個(gè)Array變量占用多少內(nèi)存旧困?
數(shù)組中的數(shù)據(jù)存放在哪里醇份?

Array變量存放哪里
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吼具,隨后出現(xiàn)的幾起案子僚纷,更是在濱河造成了極大的恐慌,老刑警劉巖拗盒,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怖竭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡陡蝇,警方通過(guò)查閱死者的電腦和手機(jī)痊臭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)哮肚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人广匙,你說(shuō)我怎么就攤上這事绽左。” “怎么了艇潭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵拼窥,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蹋凝,道長(zhǎng)鲁纠,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任鳍寂,我火速辦了婚禮改含,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迄汛。我一直安慰自己捍壤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布鞍爱。 她就那樣靜靜地躺著鹃觉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睹逃。 梳的紋絲不亂的頭發(fā)上盗扇,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音沉填,去河邊找鬼疗隶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翼闹,可吹牛的內(nèi)容都是我干的斑鼻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼猎荠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坚弱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起法牲,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤史汗,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后拒垃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓷蛙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年悼瓮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戈毒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡横堡,死狀恐怖埋市,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情命贴,我是刑警寧澤道宅,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站胸蛛,受9級(jí)特大地震影響污茵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葬项,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一泞当、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧民珍,春花似錦襟士、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝶溶,卻和暖如春章喉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背身坐。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工秸脱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人部蛇。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓摊唇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親涯鲁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巷查,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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

  • 在C語(yǔ)言中,五種基本數(shù)據(jù)類(lèi)型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來(lái)閱讀 3,333評(píng)論 0 2
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,291評(píng)論 0 6
  • 多線(xiàn)程抹腿、特別是NSOperation 和 GCD 的內(nèi)部原理岛请。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。SDWebImage的原...
    LZM輪回閱讀 2,004評(píng)論 0 12
  • 綠樹(shù)陰濃夏日長(zhǎng)警绩,樓臺(tái)倒影入池塘崇败。--《唐高駢·山亭夏日》 mach-o文件和進(jìn)程的映像(image) iOS系統(tǒng)生...
    歐陽(yáng)大哥2013閱讀 7,380評(píng)論 12 79
  • 我站在的地方叫埡 望去 是一片依然雞犬聲鬧的村 不見(jiàn)碎石小路 水泥硬化 是村里的福 曲折蜿蜒的穿過(guò) 瓦房和洋樓 在...
    心者悟道閱讀 121評(píng)論 0 5