iOS 內(nèi)存對(duì)齊原理

獲取內(nèi)存大小方式

1.sizeof
2.class_getInstanceSize
3.malloc_size

sizeof

1.sizeof是一個(gè)操作符號(hào),不是函數(shù);
2.我們一般用sizeof計(jì)算內(nèi)存大小時(shí),傳入的主要對(duì)象是數(shù)據(jù)類型,這個(gè)在編譯器的編譯階段(即編譯時(shí))就會(huì)確定大小而不是在運(yùn)行時(shí)確定,對(duì)于NSObject這樣的類而言,其定義的數(shù)據(jù)類型本質(zhì)就是一個(gè)結(jié)構(gòu)體的指針谬运,而指針的內(nèi)存大小是8字節(jié),所以對(duì)象類型占用的字節(jié)數(shù)為8字節(jié)垦藏。
3.sizeof最終得到的結(jié)果是該數(shù)據(jù)類型占用空間的大小;

class_getInstanceSize

這個(gè)方式是runtime提供的api梆暖,用于獲取類的實(shí)例對(duì)象占用的內(nèi)存空間大小,返回結(jié)果為具體字節(jié)數(shù)掂骏,本質(zhì)是獲取實(shí)例對(duì)象中成員變量占用的內(nèi)存空間轰驳。如果自定義類沒(méi)有定義屬性,僅僅只是繼承自NSObject弟灼,則這個(gè)實(shí)例對(duì)象實(shí)際占用的大小為8字節(jié)级解,使用的為8字節(jié)對(duì)齊算法

malloc_size

這個(gè)函數(shù)是獲取系統(tǒng)實(shí)際分配的內(nèi)存大小田绑,使用的為16字節(jié)對(duì)齊的算法勤哗。

可以將內(nèi)存對(duì)齊原則可以理解為以下幾點(diǎn):

原則一】 數(shù)據(jù)成員的對(duì)齊規(guī)則可以理解為min(m, n) 的公式, 其中 m表示當(dāng)前成員的開(kāi)始位置, n表示當(dāng)前成員所需要的位數(shù)。如果滿足條件 m 整除 n (即 m % n == 0), n 從 m 位置開(kāi)始存儲(chǔ), 反之繼續(xù)檢查 m+1 能否整除 n, 直到可以整除, 從而就確定了當(dāng)前成員的開(kāi)始位置掩驱。
原則二】數(shù)據(jù)成員為結(jié)構(gòu)體:當(dāng)結(jié)構(gòu)體嵌套了結(jié)構(gòu)體時(shí)芒划,作為數(shù)據(jù)成員的結(jié)構(gòu)體的自身長(zhǎng)度作為外部結(jié)構(gòu)體的最大成員的內(nèi)存大小冬竟,比如結(jié)構(gòu)體a嵌套結(jié)構(gòu)體b,b中有char民逼、int泵殴、double等,則b的自身長(zhǎng)度為8
原則三】最后結(jié)構(gòu)體的內(nèi)存大小必須是結(jié)構(gòu)體中最大成員內(nèi)存大小的整數(shù)倍缴挖,不足的需要補(bǔ)齊袋狞。

結(jié)構(gòu)體內(nèi)存對(duì)齊

內(nèi)存對(duì)齊可以理解為結(jié)構(gòu)體中的成員申請(qǐng)內(nèi)存大小時(shí)焚辅,系統(tǒng)最小分配的內(nèi)存為8字節(jié)映屋,是按每次8字節(jié)來(lái)申請(qǐng)的,不夠8字節(jié)的也會(huì)申請(qǐng)8字節(jié)同蜻,然后按結(jié)構(gòu)體中成員變量順序再次申請(qǐng)棚点,直到所有成員變量都能放下為止。

舉例來(lái)說(shuō)明
//1湾蔓、定義兩個(gè)結(jié)構(gòu)體
struct Mystruct1{
    char a;     //1字節(jié)
    double b;   //8字節(jié)
    int c;      //4字節(jié)
    short d;    //2字節(jié)
}Mystruct1;

struct Mystruct2{
    double b;   //8字節(jié)
    int c;      //4字節(jié)
    short d;    //2字節(jié)
    char a;     //1字節(jié)
}Mystruct2;

//計(jì)算 結(jié)構(gòu)體占用的內(nèi)存大小
NSLog(@"%lu-%lu",sizeof(Mystruct1),sizeof(Mystruct2));

Mystruct1Mystruct2成員一樣瘫析,只是順序不同,最后的結(jié)果是內(nèi)存大小不一樣默责。sizeof(Mystruct1) 為24,sizeof(Mystruct2))為16;贬循,如下圖所示:

結(jié)構(gòu)體內(nèi)存存儲(chǔ)示意圖

Mystruct1詳解過(guò)程:
1.Mystruct1 中每次申請(qǐng)內(nèi)存按字節(jié)最長(zhǎng)的變量來(lái)申請(qǐng),最長(zhǎng)的變量b占8個(gè)字節(jié)桃序, 變量a占一個(gè)字節(jié)杖虾,申請(qǐng)只能按8字節(jié)申請(qǐng),實(shí)際只使用了一個(gè)字節(jié)媒熊;
2.變量b占8個(gè)字節(jié)奇适,如果順序存放則會(huì)被分割到2個(gè)字節(jié)中,一個(gè)存放7個(gè)另一個(gè)存放1個(gè)芦鳍,這樣的話取值時(shí)就會(huì)錯(cuò)亂嚷往,為了按正確的偏移位置取到正確的值,系統(tǒng)按每次8個(gè)字節(jié)的偏移量來(lái)讀取內(nèi)存柠衅。這樣的結(jié)果就是就算a只用了一個(gè)字節(jié)還有7個(gè)未用皮仁,接下來(lái)的b占8字節(jié)也要重新分配至少能存放下b的新內(nèi)存,再次申請(qǐng)一個(gè)8字節(jié)內(nèi)存菲宴;
3.變量c占4個(gè)字節(jié)贷祈,存放在第三次申請(qǐng)的8字節(jié)的內(nèi)存,還有4字節(jié)沒(méi)有用到裙顽,變量d占2字節(jié)付燥,可以存放在c所在的8字節(jié)內(nèi)存中,所有申請(qǐng)的內(nèi)存加起來(lái)為24個(gè)字節(jié)大小愈犹,雖然實(shí)際只使用了15字節(jié)键科。

Mystruct2詳解過(guò)程:
1.Mystruct2 中每次申請(qǐng)內(nèi)存按字節(jié)最長(zhǎng)的變量來(lái)申請(qǐng)闻丑,變量b占8個(gè)字節(jié),第一次申請(qǐng)的內(nèi)存全部用來(lái)存放b勋颖;
2.變量c占4字節(jié)嗦嗡,第二次申請(qǐng)的內(nèi)存存放c后還剩4個(gè)字節(jié)沒(méi)用用到,d占2字節(jié)饭玲,可以存放侥祭,還剩2字節(jié),變量a占一個(gè)字節(jié)茄厘,也可以存放矮冬,這樣存放后,還剩一個(gè)字節(jié)空余次哈,所有申請(qǐng)的內(nèi)存加起來(lái)為16胎署,雖然實(shí)際只用了15個(gè)字節(jié)。

嵌套結(jié)構(gòu)體內(nèi)存對(duì)齊

嵌套結(jié)構(gòu)體內(nèi)存對(duì)齊詳解:

//1窑滞、結(jié)構(gòu)體嵌套結(jié)構(gòu)體
struct Mystruct3{
    double b;   //8字節(jié)
    int c;      //4字節(jié)
    short d;    //2字節(jié)
    char a;     //1字節(jié)
    struct Mystruct2 str; 
}Mystruct3;

//2琼牧、打印 Mystruct3 的內(nèi)存大小
NSLog(@"Mystruct3內(nèi)存大小:%lu", sizeof(Mystruct3));
NSLog(@"Mystruct3中結(jié)構(gòu)體成員內(nèi)存大邪馈:%lu", sizeof(Mystruct3.str));

//先說(shuō)結(jié)果Mystruct3內(nèi)存大芯薹弧:32,
//Mystruct3中結(jié)構(gòu)體成員內(nèi)存大写烁摹:16

分析Mystruct3計(jì)算過(guò)程如下:
1.結(jié)構(gòu)體成員Mystruct2 str是一個(gè)結(jié)構(gòu)體趾撵,根據(jù)內(nèi)存對(duì)齊原則二,Mystruct2中最大的成員大小為8带斑,b,c,d,a最大字節(jié)為8鼓寺,所以每次申請(qǐng)按8字節(jié)大小來(lái);
2.b,c,d,a內(nèi)存分析和Mystruct2 str一樣勋磕,內(nèi)存大小為16妈候,加上str類型也為Mystruct2 str,也是16挂滓,總共大小為32苦银;

內(nèi)存優(yōu)化(屬性重排)

從上面的分析可知,結(jié)構(gòu)體內(nèi)存大小與結(jié)構(gòu)體成員的順序有關(guān).

當(dāng)結(jié)構(gòu)體成員內(nèi)存小的在前面時(shí)會(huì)因?yàn)閮?nèi)存對(duì)齊的原因比較浪費(fèi)內(nèi)存赶站,為了解決這個(gè)問(wèn)題蘋果中采用空間換時(shí)間幔虏,將類中的屬性進(jìn)行重排,以此來(lái)達(dá)到內(nèi)存優(yōu)化的目的

總結(jié)

1.大部分的內(nèi)存都是通過(guò)固定的內(nèi)存快進(jìn)行讀缺创弧想括;
2.盡管我們?cè)趦?nèi)存中采取了內(nèi)存對(duì)齊的方式,但是并不是所有的內(nèi)存都是可以進(jìn)行浪費(fèi)的烙博,蘋果會(huì)自動(dòng)進(jìn)行屬性重排以此來(lái)優(yōu)化內(nèi)存瑟蜈;

class_getInstanceSize:采用8字節(jié)對(duì)齊烟逊,參照的對(duì)象的屬性內(nèi)存大小铺根;
malloc_size:采用16字節(jié)對(duì)齊宪躯,參照整個(gè)對(duì)象的內(nèi)存大小,對(duì)象實(shí)際分配的內(nèi)存大小必須是16的整數(shù)倍位迂。

[參考鏈接]http://www.reibang.com/p/2b660ec22fe0访雪;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市掂林,隨后出現(xiàn)的幾起案子臣缀,更是在濱河造成了極大的恐慌,老刑警劉巖党饮,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肝陪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡刑顺,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門饲常,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蹲堂,“玉大人,你說(shuō)我怎么就攤上這事贝淤∑饩海” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵播聪,是天一觀的道長(zhǎng)朽基。 經(jīng)常有香客問(wèn)我,道長(zhǎng)离陶,這世上最難降的妖魔是什么稼虎? 我笑而不...
    開(kāi)封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮招刨,結(jié)果婚禮上霎俩,老公的妹妹穿的比我還像新娘。我一直安慰自己沉眶,他們只是感情好打却,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著谎倔,像睡著了一般柳击。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上片习,一...
    開(kāi)封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天捌肴,我揣著相機(jī)與錄音彤守,去河邊找鬼。 笑死哭靖,一個(gè)胖子當(dāng)著我的面吹牛具垫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播试幽,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼筝蚕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铺坞?” 一聲冷哼從身側(cè)響起起宽,我...
    開(kāi)封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎济榨,沒(méi)想到半個(gè)月后坯沪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擒滑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年腐晾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丐一。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藻糖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出库车,到底是詐尸還是另有隱情巨柒,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布柠衍,位于F島的核電站洋满,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏珍坊。R本人自食惡果不足惜牺勾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垫蛆。 院中可真熱鬧禽最,春花似錦、人聲如沸袱饭。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)虑乖。三九已至懦趋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疹味,已是汗流浹背仅叫。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工帜篇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诫咱。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓笙隙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親坎缭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竟痰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359