手撕 iOS 底層04 -- 內存對齊原理

本章主要由結構體內存對齊到蘋果的屬性重排挺物, 以及16字節(jié)對齊算法

0x00 -- 獲取內存大小的三種方式

LGPerson *person = [LGPerson alloc];
person.name      = @"Cooci";
person.nickName  = @"KC";
NSLog(@"%@ - %lu - %lu - %lu",person,sizeof(person),class_getInstanceSize([LGPerson class]),malloc_size((__bridge const void *)(person)));
// 輸出 8 - 40 - 48

獲取內存大小的三種方式:

  • sizeof(expression-or-type)

小提示 ??: sizeof的三種語法形式:

        int a = 10;
        size_t a1 = sizeof(a); // 4
        size_t a2 = sizeof a;  // 4
        size_t a3 = sizeof(int); // 4
        int *pa = &a; 
        size_t p1 = sizeof(pa); // 8
        size_t p2 = sizeof pa;  // 8
        size_t p3 = sizeof(int *); // 8

        NSObject *obj = [NSObject alloc] ; 
        size_t o1 = sizeof(obj); // 8
        size_t o2 = sizeof obj; // 8
        size_t o3 = sizeof(NSObject*);// 8

sizeof()是操作符直焙,不是函數(shù)撩扒;其作用是返回一個對象或者類型所占的內存字節(jié)數(shù)。

基本數(shù)據(jù)類型int,char,double,float等這樣簡單內置數(shù)據(jù)類型扩然,它們的大小和系統(tǒng)相關掸犬, 不同系統(tǒng)下取值也不一樣。

如果是結構體通殃,sizeof涉及到字節(jié)對齊的問題度液,根據(jù)計算機組成原理教導我們這樣有助于加快計算機的取數(shù)速度,否則多話指令周期画舌。讓寬度為2的節(jié)本數(shù)據(jù)類型short等堕担,都位于能被2整除的低智商;讓寬度為4的基本數(shù)據(jù)類型int等骗炉,都位于能被4整除的地址上照宝,以此類推, 這樣句葵,倆個數(shù)中間就可能需要加入填充的字節(jié)厕鹃,所以整個結構體的sizeof值就增長了。詳細對齊規(guī)則看文章下方結構體對齊乍丈。 這里不再贅述剂碴。

  • class_getInstanceSize
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}

// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
    return word_align(unalignedInstanceSize());
}

#ifdef __LP64__
#   define WORD_SHIFT 3UL
#   define WORD_MASK 7UL
#   define WORD_BITS 64
#else
#   define WORD_SHIFT 2UL
#   define WORD_MASK 3UL
#   define WORD_BITS 32
#endif

static inline uint32_t word_align(uint32_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}

這個函數(shù)是runtime提供的一個API函數(shù),獲取類的實例對象所占用的內存大小轻专。

通過源碼可知道 class_getInstanceSize函數(shù)獲取的的對象大小是8字節(jié)對齊忆矛。

這個函數(shù)依據(jù)對象內部的屬性變化而變化;如果沒有屬性, 只繼承了NSObject催训,則類的實例對象實際占用的內存大小是8洽议,

  • malloc_size

malloc_size是系統(tǒng)實際開辟的內存空間,class_getInstanceSize是實際占用的空間漫拭。

根據(jù)文章頂部代碼實例1打印可驗證亚兄。這個是由系統(tǒng)完成的,從上面的分析看得出采驻, 實際占用和實際分配的大小是不一樣的审胚。


0x01 -- 結構體內存對齊

這里可以參考我之前寫的文章底層必備c/c++知識結構體

struct LGStruct1 {
    double d; // 0-7
    char c;     //8
    int i;
    short s;      //9 10 11 12 13 14 15
};

struct LGStruct2 {
    double d;           //8 0-7
    int i;              //4 8-11
    char c;             //1 12
    short s;            //2 13 14 15
};

int main() {
        NSLog(@"%lu", sizeof(struct LGStruct1)); // 24
              NSLog(@"%lu", sizeof(struct LGStruct2));  // 16
  return 0;
}

上面片段代碼Test1Test2sizeof是多少?

從打印可得知LGStruct1的內存大小為24; LGStruct216;

倆個結構體 礼旅,數(shù)據(jù)類型一致膳叨,順序不一樣, 導致輸出的結果也不一樣痘系, 這就涉及到內存對齊菲嘴;

至于為什么系統(tǒng)要做這件事; 上面說sizeof的時候也說了, 簡單來說碎浇,提高性能临谱。

內存對齊規(guī)則

  • 【原則一】 數(shù)據(jù)成員的對齊規(guī)則可以理解為min(m, n) 的公式, 其中 m表示當前成員的開始位置, n表示當前成員所需要的位數(shù)。如果滿足條件 m 整除 n (即 m % n == 0), nm 位置開始存儲, 反之繼續(xù)檢查 m+1 能否整除 n, 直到可以整除, 從而就確定了當前成員的開始位置奴璃。

  • 【原則二】數(shù)據(jù)成員為結構體:當結構體嵌套了結構體時悉默,作為數(shù)據(jù)成員的結構體的自身長度作為外部結構體的最大成員的內存大小,比如結構體a嵌套結構體b苟穆,b中有char抄课、int、double等雳旅,則b的自身長度為8

  • 【原則三】最后結構體的內存大小必須是結構體中最大成員內存大小的整數(shù)倍跟磨,不足的需要補齊。

對齊規(guī)則驗證

根據(jù)上面的實例代碼攒盈, 畫了一章對齊示意圖

結構體內存對齊示意圖.png
  • 根據(jù)規(guī)則一 進行內部成員對齊抵拘。所占用字節(jié)18個;
  • 根據(jù)規(guī)則三 整體對齊后型豁,占用字節(jié)24個僵蛛。

結構體嵌套對齊

struct mystruct4 {
    int a;
    struct mystruct5 {
        short c;
        double b;
        char c1;
    }str5;
    int d;
}s4;

printf("mystruct4內存大小 %lu\n", sizeof(s4)); // 40
printf("mystruct5內存大小 %lu\n", sizeof(s4.str5)); // 24

結構體嵌套對齊的算法規(guī)則是

  1. int0開始, 占4個字節(jié)迎变, 位置是0 1 2 3充尉。
  2. str5按照規(guī)則二從double算, 空白填充4 5 6 7;從8-24是嵌套結構體所占大小衣形。
  3. 接著25,不滿足規(guī)則一驼侠,25 26 27填充空白, 28 29 30 31占位。
  4. 一共使用了32個字節(jié)倒源,按照規(guī)則三整體對齊苛预,是40個字節(jié)。

0x02 -- 內存優(yōu)化(屬性重排)

x指令 打印對象內存地址 == memory read person

x/4gx 以16進制打4個印人可以方便看的內存

@interface Other: NSObject
  @property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic) char sex;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) long height;
@property (nonatomic) char garde;
@end
  @implementation
  @end

Other *person = [Other alloc];
person.name      = @"liming";
person.nickName  = @"ll";
person.sex = "m";
person.garde = "A";
person.age = 23;
x:8gx.jpg

通過LLDB命令查看對象的內存布局相速。x命令查看的不夠直觀碟渺,因為iOS是小端模式鲜锚,所以是內存值是倒著突诬,使用x/4gx打印出來的方便直接查看。

查看對象內存.jpg

通過打印芜繁,把對象存儲的值都直觀的輸出了旺隙, 而且在0x000000170000414d這個值里存儲了對象里屬性三個值,這就是屬性重排骏令,雖然對象編譯到底層是結構體蔬捷,按照結構體對齊,會極大的浪費空間 榔袋,蘋果在這一層又做了優(yōu)化周拐,就是屬性重排,達到優(yōu)化空間的目的。利用空間換時間

參考

結構體內存對齊


歡迎大佬留言指正??凰兑,碼字不易妥粟,覺得好給個贊?? 有任何表達或者理解失誤請留言交流;共同進步吏够;

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末勾给,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锅知,更是在濱河造成了極大的恐慌播急,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件售睹,死亡現(xiàn)場離奇詭異桩警,居然都是意外死亡,警方通過查閱死者的電腦和手機昌妹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門捶枢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捺宗,你說我怎么就攤上這事柱蟀。” “怎么了蚜厉?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵长已,是天一觀的道長。 經(jīng)常有香客問我,道長术瓮,這世上最難降的妖魔是什么康聂? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮胞四,結果婚禮上恬汁,老公的妹妹穿的比我還像新娘。我一直安慰自己辜伟,他們只是感情好氓侧,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著导狡,像睡著了一般约巷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旱捧,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天独郎,我揣著相機與錄音,去河邊找鬼枚赡。 笑死氓癌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的贫橙。 我是一名探鬼主播贪婉,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼料皇!你這毒婦竟也來了谓松?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤践剂,失蹤者是張志新(化名)和其女友劉穎鬼譬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逊脯,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡优质,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了军洼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巩螃。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖匕争,靈堂內的尸體忽然破棺而出避乏,到底是詐尸還是另有隱情,我是刑警寧澤甘桑,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布拍皮,位于F島的核電站歹叮,受9級特大地震影響,放射性物質發(fā)生泄漏铆帽。R本人自食惡果不足惜咆耿,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爹橱。 院中可真熱鬧萨螺,春花似錦、人聲如沸愧驱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冯键。三九已至惹盼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惫确,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工蚯舱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留改化,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓枉昏,卻偏偏與公主長得像陈肛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兄裂,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容