iOS底層原理--02 :內(nèi)存對齊原理

  • 研究內(nèi)存對齊原理之前缔赠,我們先要熟悉下表:


    類型對應(yīng)表.jpg

    知道對應(yīng)的內(nèi)存大小了涨醋,接下來我們需要獲取內(nèi)存,驗證是否正確郁季。

  • 驗證內(nèi)存的三種方式:
    1冷溃、sizeof
    2钱磅、class_getInstanceSize
    3、malloc_size

sizeof
  • 1似枕、sizeof是一個操作符盖淡,不是函數(shù)
  • 2、sizeof計算的是對象數(shù)據(jù)類型的大小凿歼,這個大小在編譯時確定的而不是運行時
  • 3褪迟、sizeof最終得到的數(shù)據(jù)是該數(shù)據(jù)類型占用空間的大小,當sizeof(結(jié)構(gòu)體)的時候答憔,獲取到的是對象指針大小味赃,我們知道一個指針的內(nèi)存大小是8,所以sizeof獲取內(nèi)存大小時可以放基本數(shù)據(jù)類型虐拓、對象心俗、指針、
calss_getInstanceSize

這個方法是runtime提供的api蓉驹,用于獲取類的實例對象所占用的內(nèi)存大小另凌,并返回具體的字節(jié)數(shù),其本質(zhì)就是獲取實例對象中成員變量的內(nèi)存大小

malloc_size

這個函數(shù)是 獲取系統(tǒng)實際分配的內(nèi)存大小

通過下面的函數(shù)打印結(jié)果驗證上面的說法:

#import <Foundation/Foundation.h>
#import "LGPerson.h"
#import <objc/runtime.h>
#import <malloc/malloc.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *objc = [[NSObject alloc] init];
        NSLog(@"objc對象類型占用的內(nèi)存大薪溽!:%lu",sizeof(objc));
        NSLog(@"objc對象實際占用的內(nèi)存大蟹托弧:%lu",class_getInstanceSize([objc class]));
        NSLog(@"objc對象實際分配的內(nèi)存大小:%lu",malloc_size((__bridge const void*)(objc)));
    }
    return 0;
}

打印結(jié)果如下:

三種獲取內(nèi)存方式的打印結(jié)果.png

從打印的結(jié)果看實際分配的內(nèi)存和實際內(nèi)存大小并不相等诗茎,不相等的原因是因為內(nèi)存16字節(jié)對齊的原則導(dǎo)致的工坊,內(nèi)存字節(jié)對齊的原理主要有以下三點:
1、數(shù)據(jù)成員對齊規(guī)則:struct 或者 union 的數(shù)據(jù)成員敢订,第一個數(shù)據(jù)成員放在offset=0的地方王污,以后每個數(shù)據(jù)成員存儲的其實位置要從該成員大小或者成員子成員大小(只要該成員有子成員比如結(jié)構(gòu)體)的整數(shù)倍開始(例如int在32位機中占4字節(jié)楚午,則要從4的整數(shù)倍地址開始存儲)
2昭齐、數(shù)據(jù)成員位結(jié)構(gòu)體:如果一個結(jié)構(gòu)體里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲(例如:struct a里面存有struct b矾柜,b里面有char阱驾、int、double等元素怪蔑,則b應(yīng)該從8的整數(shù)倍開始存儲)
3里覆、結(jié)構(gòu)體的整體對齊規(guī)則:結(jié)構(gòu)體的總大小,即 sizeof的結(jié)果必須是其內(nèi)部最大成員的整數(shù)倍缆瓣,不足的要補齊

為什么是16位對齊

1喧枷、通常內(nèi)存是一個個字節(jié)組成的,cpu在存取數(shù)據(jù)時,并不是以字節(jié)為單位存儲隧甚,而是以塊為單位存取车荔,塊的大小為內(nèi)存存取力度,頻繁存取字節(jié)未對齊的數(shù)據(jù)戚扳,會極大降低CPU的性能夸赫,所以可以通過減少存取次數(shù)來降低cup的開銷
2、16字節(jié)對齊是因為一個對象中的第一個屬性isa8字節(jié)咖城,當然對象中肯定還有其他屬性茬腿,當無屬性時會預(yù)留8字節(jié),即16字節(jié)對齊宜雀,如果不預(yù)留相當于這個對象的isa和其它對象的isa緊挨著切平,容易造成訪問混亂
3、16字節(jié)對齊后辐董,可以加快cpu的存取速度悴品,同時增加訪問安全性

16字節(jié)對齊的算法
  • 首先將原始的內(nèi)存 8 與 size_t(15)相加,得到 8 + 15 = 23
  • 將 size_t(15) 即 15進行(取反)操作简烘,(取反)的規(guī)則是:1變?yōu)?苔严,0變?yōu)?
  • 最后將 23 與 15的取反結(jié)果 進行 &(與)操作,&(與)的規(guī)則是:都是1為1孤澎,反之為0届氢,最后的結(jié)果為 16,即內(nèi)存的大小是以16的倍數(shù)增加的


    內(nèi)存16字節(jié)對齊算法.png

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

接下來我們定義兩個結(jié)構(gòu)體分別計算他們的大懈残瘛:

//1退子、定義兩個結(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;

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

輸出結(jié)果為:

a0000000bbbbbbbbccccdd =24
bbbbbbbbccccdda0=16 //結(jié)構(gòu)體的大小(sizeof)必須是最大成員的整數(shù)倍型将,所以15位需要補一位最后結(jié)果是16

兩個結(jié)構(gòu)體乍一看寂祥,沒什么區(qū)別,其中定義的變量 和 變量類型都是一致的七兜,唯一的區(qū)別只是在于定義變量的順序不一致丸凭,那為什么他們做占用的內(nèi)存大小不相等呢?其實這就是iOS中的內(nèi)存字節(jié)對齊現(xiàn)象

可以將內(nèi)存對齊原則可以理解為以下兩點:

*【原則一】 數(shù)據(jù)成員的對齊規(guī)則可以理解為min(m, n) 的公式, 其中 m表示當前成員的開始位置, n表示當前成員所需要的位數(shù)腕铸。如果滿足條件 m 整除 n (即m % n == 0), nm 位置開始存儲, 反之繼續(xù)檢查 m+1 能否整除 n, 直到可以整除, 從而就確定了當前成員的開始位置惜犀。
*【原則二】數(shù)據(jù)成員為結(jié)構(gòu)體:當結(jié)構(gòu)體嵌套了結(jié)構(gòu)體時,作為數(shù)據(jù)成員的結(jié)構(gòu)體的自身長度作為外部結(jié)構(gòu)體的最大成員的內(nèi)存大小恬惯,比如結(jié)構(gòu)體a嵌套結(jié)構(gòu)體b向拆,b中有charint酪耳、double等,則b的自身長度為8
*【原則三】最后結(jié)構(gòu)體的內(nèi)存大小必須是結(jié)構(gòu)體中最大成員內(nèi)存大小的整數(shù)倍,不足的需要補齊碗暗。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颈将,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子言疗,更是在濱河造成了極大的恐慌晴圾,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪奄,死亡現(xiàn)場離奇詭異死姚,居然都是意外死亡,警方通過查閱死者的電腦和手機勤篮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門都毒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碰缔,你說我怎么就攤上這事账劲。” “怎么了金抡?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵瀑焦,是天一觀的道長。 經(jīng)常有香客問我梗肝,道長榛瓮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任巫击,我火速辦了婚禮榆芦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喘鸟。我一直安慰自己匆绣,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布什黑。 她就那樣靜靜地躺著崎淳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愕把。 梳的紋絲不亂的頭發(fā)上拣凹,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音恨豁,去河邊找鬼嚣镜。 笑死,一個胖子當著我的面吹牛橘蜜,可吹牛的內(nèi)容都是我干的菊匿。 我是一名探鬼主播付呕,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跌捆!你這毒婦竟也來了徽职?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤佩厚,失蹤者是張志新(化名)和其女友劉穎姆钉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抄瓦,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡潮瓶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钙姊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毯辅。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖摸恍,靈堂內(nèi)的尸體忽然破棺而出悉罕,到底是詐尸還是另有隱情,我是刑警寧澤立镶,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布壁袄,位于F島的核電站,受9級特大地震影響媚媒,放射性物質(zhì)發(fā)生泄漏嗜逻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一缭召、第九天 我趴在偏房一處隱蔽的房頂上張望栈顷。 院中可真熱鬧,春花似錦嵌巷、人聲如沸萄凤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽靡努。三九已至,卻和暖如春晓折,著一層夾襖步出監(jiān)牢的瞬間惑朦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工漓概, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漾月,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓胃珍,卻偏偏與公主長得像梁肿,于是被迫代替她去往敵國和親蜓陌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355