iOS的內(nèi)存對齊

struct LGStruct1 {
    char b;         
    int c;          
    double a;     
    short d;      
}struct1;

struct LGStruct2 {
    double a;          
    int c;             
    char b;           
    short d;            
}struct2;

struct1 和struct2的內(nèi)存大小一致嘛,同樣的數(shù)據(jù)結(jié)構(gòu),內(nèi)存的大小應(yīng)該是一樣的呀!不要輕易的下結(jié)論,因為cpu在讀取數(shù)據(jù)的時候,都是一整塊一整塊的讀取,如果說每一塊的大小都不一樣,那么在每一次讀取的時候,還需要計算每一塊數(shù)據(jù)的大小,根據(jù)大小去讀取,這樣就浪費了時間的資源。所以,cpu在讀取數(shù)據(jù)的的時候,讀取的是一塊固定的大小,那么這個大小是怎么決定呢,根據(jù)數(shù)據(jù)中最大的單位去作為空間單元,這樣就可以把每個數(shù)據(jù)都裝進(jìn)去了,這就是通過空間來換取時間的便利。

  每一個數(shù)據(jù)都分配同樣的大小嘛,并不是的,所以就引出了上面的經(jīng)典問題,兩個會一致嘛,其實打印內(nèi)存大小即可得知,struct1的內(nèi)存大小為24,struct2的內(nèi)存大小為16,這又是為什么呢,這里用空間換時間也不能極大的浪費,所以,這里就引入了一個內(nèi)存對齊的概念。

在這兩個結(jié)構(gòu)體中,占據(jù)內(nèi)存最大的類型為double,8個字節(jié),那么結(jié)構(gòu)體的每一塊都是為8字節(jié),struct1 排列順序為 char b; 1 字節(jié) int c; 4字節(jié) double a; 8字節(jié) short d; 2字節(jié)。 所以這里第一次分配的8字節(jié),先將char b 填充,此時這8個字節(jié)的內(nèi)存地址中,只有第一位裝了一個char類型,后面還有七個位置,是不是很浪費。所以將int c也填充到到后面的位置,應(yīng)該怎么放呢,這里其實是有規(guī)則的:
填充的位置必須可以整除該數(shù)據(jù)的大小,以int c為例,填充的起始坐標(biāo)就為4
后續(xù)的大小必須可以填充完整個數(shù)據(jù),同樣,4 ~ 7 4個坐標(biāo)可以放下4字節(jié)的int
所以,可以看看第一個分配的8字節(jié)都填充了什么數(shù)據(jù)
b 、、、c1 c2 c3 c4
0 1 2 3 4 5 6 7
同理,double a占據(jù)了第二個分配的8字節(jié)
此時 還有一個short 兩字節(jié)的,只能再分配一個8字節(jié)出來,這樣struct1分配的總大小即為24

分析struct2 double a占據(jù)了第一個分配的8字節(jié),第二個分配的8字節(jié)
c1 c2 c3 c4 b 、 d1 d2
0 1 2 3 4 5 6 7
所以struct2 分配的大小即為 16 字節(jié)

再來看

struct LGStruct3 {
   double a; // 0 - 7    8字節(jié)*1
   int b;    // 8 - 11
   char c;   // 12。     8字節(jié)*2
   struct LGStruct1 str1;  // 24字節(jié)*1
   short d;  // 40 - 41
   int e;    // 44 -47   8字節(jié)*3
   struct LGStruct2 str2; // 16字節(jié)*1
}struct3;

struct3 的內(nèi)存大小為 64 ,是不是又覺得很神奇,這里要說明的一點是,結(jié)構(gòu)體不能作為基礎(chǔ)的計算單元,根據(jù)結(jié)構(gòu)體內(nèi)部的最基礎(chǔ)的數(shù)據(jù)作為計算單元。

內(nèi)存對齊不只是基礎(chǔ)的數(shù)據(jù),在alloc中我們發(fā)現(xiàn)了一個對象內(nèi)存對齊是根據(jù)8字節(jié),但是一個對象開辟出來最低是16字節(jié),那么影響一個對象內(nèi)存大小的因素有哪些呢,對象的內(nèi)存對齊是否和結(jié)構(gòu)體一致呢。

首先創(chuàng)建一個類,這個類擁有屬性、 方法 、 變量、 協(xié)議、 分類 、擴(kuò)展
一個個排除,多測試幾次即可得知,只有變量會和屬性會影響開辟的內(nèi)存大小,而屬性沒有set和get方法本質(zhì)就是一個變量,所以根源的影響還是變量。

person類

賦值

這里通過lldb的命令來調(diào)試

依照上面的規(guī)則,person 在設(shè)置了這7個屬性之后至少需要64個字節(jié),但是通過lldb命令得出


lldb控制臺

這里只需要48個字節(jié),那么做了哪些優(yōu)化呢

打印內(nèi)存存儲的數(shù)據(jù)

根據(jù)打印的數(shù)據(jù),我么只找到了4個屬性,那么其他的三個屬性呢,其實,這里蘋果對于內(nèi)存的優(yōu)化非常到位,內(nèi)存地址第一排的第二個地址


消失的屬性

打印出來是錯的啊,不要著急,根據(jù)內(nèi)存對齊原則拆分一下內(nèi)存地址


拆分內(nèi)存地址

拆分完即可看到,有三個屬性,age出來了,但是98和97是什么,其實98和97是ASCII表中對應(yīng)的b和a。

這樣這個對象的內(nèi)存大小就可以確定了,了解了這些,在操作底層的一些數(shù)據(jù)的時候,可以相對更優(yōu)的利用內(nèi)存。

補(bǔ)充一下內(nèi)存對齊的算法
n為對齊的總數(shù)

算法一
align 為根據(jù)幾對齊
((n + align - 1) & (~(align - 1)))

算法二
m 是 2的m次方 = 根據(jù)幾對齊
n >> m。n<< m

這兩個算法沒什么區(qū)別,主要作用是將數(shù)據(jù)的二進(jìn)制的后m位變成0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇文章我們來探索一下iOS內(nèi)存對齊的原理,在探索完內(nèi)存對齊原理之后,你就會明白內(nèi)存對齊的好處。 在講述內(nèi)存對齊時...
    大橘豬豬俠閱讀 1,045評論 0 3
  • 什么是內(nèi)存對齊? 在C語言中,結(jié)構(gòu)是一種復(fù)合數(shù)據(jù)類型,其構(gòu)成元素既可以是基本數(shù)據(jù)類型(如int、long、floa...
    _Luyouli閱讀 285評論 0 2
  • 一、結(jié)構(gòu)體內(nèi)存對齊 1.1 結(jié)構(gòu)體內(nèi)存對齊三大原則 數(shù)據(jù)成員對?規(guī)則結(jié)構(gòu)體(struct)或聯(lián)合體(union)的...
    HotPotCat閱讀 619評論 1 3
  • iOS 內(nèi)存對其原則 數(shù)據(jù)成員對?規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第?個數(shù)據(jù)成員放在...
    Gumball_a45f閱讀 302評論 0 0
  • 內(nèi)存對齊的規(guī)則 1.數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)或聯(lián)合的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)...
    順7zi燃閱讀 460評論 0 1

友情鏈接更多精彩內(nèi)容