02 - 內(nèi)存對齊解析-結(jié)構(gòu)體嵌套結(jié)構(gòu)體

一 思考

struct Person{
   int a;
   char b;
   double c;
} person;

struct People{
    char b;
    double c;
    int a;
}people;
int main ()
{
    printf ("%d\n",sizeof(people);  
   printf ("%d\n",sizeof(person);  
    return 0;
}
各類型所占內(nèi)存大小

真機(jī)運(yùn)行,64位系統(tǒng)上 char + int + double = 1 + 4 + 8 應(yīng)該占12個字節(jié) ,但運(yùn)行打印后發(fā)現(xiàn)為24 ,16,說明系統(tǒng)存儲相應(yīng)類型有其固定方式即為內(nèi)存對齊

一 為什么要內(nèi)存對齊

為了提高程序的性能磕蒲,數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊,為了訪問未對齊的內(nèi)存履磨,處理器需要作兩次內(nèi)存訪問真椿;然而,對齊的內(nèi)存訪問僅需要一次訪問. 例如2-5 4字節(jié)數(shù)據(jù),在沒有內(nèi)存對齊的情況下要取兩次 0-3 4-7 才能得到2-5所需數(shù)據(jù).

二 規(guī)則 - 如何計算

  • 假設(shè)m為當(dāng)前成員起始存儲位置 n為其所需存儲大小 需滿足 m % n == 0
    否則需從m+1位開始 直到滿足條件
  • 當(dāng)結(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開始計算b結(jié)構(gòu)體內(nèi)子成員位置
  • 最后結(jié)構(gòu)體的內(nèi)存大小必須是結(jié)構(gòu)體中最大成員內(nèi)存大小的整數(shù)倍袁铐,不足的需要補(bǔ)齊

解釋下上面的24 16 是如何得到的:

Person 結(jié)構(gòu)結(jié)構(gòu)體
計算思路
  • int a 占4個字節(jié)從頭開始
  • chat b 一個字節(jié) 占據(jù) 4號位
  • double 8個字節(jié) 5, 6 , 7, 無法整除8 故偏移到8號位置 開始到15號 共占8位
  • 結(jié)構(gòu)體總大小位置為16 最大成員為double c8位 可被16整除 故返回16個字節(jié)
People 結(jié)構(gòu)結(jié)構(gòu)體
計算思路
  • chat b 從0開始 占一個字節(jié)
  • double c8個字節(jié)偏移到8號位置向后8位到15
    -int a 4字節(jié)可以被16整除 從16開始向后4位到19
  • 最大成員為double c8位, 向后補(bǔ)齊到23 ,共24位可整除8,返回24個字節(jié)
三 結(jié)構(gòu)體嵌套結(jié)構(gòu)體
struct Teacher{
    char d;
    int e;
    short f;
    int g;
}teacher;

struct tClass{
    char a;
    int b;
    short c; 
    struct Teacher teacher1;
}class;

int main ()
{
    printf ("%d\n",sizeof(class); //28
    return 0;
}
計算過程
  • chat a , int b , short c 如上面結(jié)構(gòu)體一樣計算到位置9
  • Class中最大成員為int 4字節(jié) 所以偏移到12號位置存儲class中的chat d
  • 剩下的類似普通結(jié)構(gòu)體直到27號位置存儲完共28位 28 可以整除最大成員大小 int 4字節(jié) 返回28

三 拓展, 應(yīng)用

  • pragma pack(n) & attribute((aligned (n)))

#pragma pack(1)
struct Person{
  int a;
  char b;
  double c;
} person;// sizeof(person) =  13
#pragma pack()

#define PACKED __attribute__((packed))
struct  PACKED People{
   char b;
   double c;
   int a;
}people;//sizeof(people) =  13
  • #pragma pack(n)為設(shè)置采用多少字節(jié)對齊
  • #define PACKED __attribute__((packed)) 取消編譯過程中的優(yōu)化對齊

四 OC中的內(nèi)存優(yōu)化

  • 由 Person 與People 我們可以得知,在啟用內(nèi)存對齊后,成員相同的結(jié)構(gòu)體,成員順序不同,則最后實際開辟內(nèi)存大小也不同,并且所占內(nèi)存大小大的成員在結(jié)構(gòu)體位置靠前時,最終開辟的空間可能會更小. 不過OC中采用的是16字節(jié)對齊,這種方式優(yōu)化沒意義.

OC 屬性重排驗證

@interface Person : NSObject

@property(nonatomic,assign)NSInteger age;

@property(nonatomic,assign)BOOL sex;

@property(nonatomic,copy)NSString *name;

@property(nonatomic,copy)NSString *address;

@end

-聲明一個對象Person 其屬性順序如上

  • 賦值
   Person *person = [[Person alloc] init];
   person.name = @"范熱熱";
   person.address = @"li bed";
   person.age = 100;
   person.height = 400;
   person.a = 'f';
   person.b = 'b';
  
   NSLog(@"objc對象類型占用的內(nèi)存大薪已选:%lu",sizeof(person));
   NSLog(@"objc對象實際占用的內(nèi)存大泻峄搿:%lu",class_getInstanceSize([Person class]));
   NSLog(@"objc對象分配的內(nèi)存大小:%lu",malloc_size((__bridge const void*)(person)));
  

查看打印結(jié)果 為 8 40 48

  • sizeof(person) 得到的是person指針的大小 占8位 沒毛病
  • malloc_size((__bridge const void*)(person)) 實際開辟的大小,采用16字節(jié)對齊要被16整除 得48 也可以
  • class_getInstanceSize([Person class]) 這個40是如何得到呢 答案是蘋果實際采用的是8字節(jié)對齊 驗證一下


    person 內(nèi)存分布
  • 首先我們發(fā)現(xiàn) 實際內(nèi)存中存儲的屬性值與我們在.h中定義的順序并不一樣
  • 第一個占8位的為ISA指針地址
  • 第二個8位 一共包含了 int age chat a chat b三個屬性
  • 第三個8位 為 int height
  • 第四個第五個8位為 NSString 類型
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屉更,一起剝皮案震驚了整個濱河市徙融,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瑰谜,老刑警劉巖欺冀,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異萨脑,居然都是意外死亡隐轩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門渤早,熙熙樓的掌柜王于貴愁眉苦臉地迎上來职车,“玉大人,你說我怎么就攤上這事蛛芥√崮瘢” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵仅淑,是天一觀的道長称勋。 經(jīng)常有香客問我,道長涯竟,這世上最難降的妖魔是什么赡鲜? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮庐船,結(jié)果婚禮上银酬,老公的妹妹穿的比我還像新娘。我一直安慰自己筐钟,他們只是感情好揩瞪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篓冲,像睡著了一般李破。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壹将,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天嗤攻,我揣著相機(jī)與錄音,去河邊找鬼诽俯。 笑死妇菱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闯团,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼辛臊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了偷俭?” 一聲冷哼從身側(cè)響起浪讳,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涌萤,沒想到半個月后淹遵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡负溪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年透揣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片川抡。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡辐真,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出崖堤,到底是詐尸還是另有隱情侍咱,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布密幔,位于F島的核電站楔脯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胯甩。R本人自食惡果不足惜昧廷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望偎箫。 院中可真熱鬧木柬,春花似錦、人聲如沸淹办。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怜森。三九已至齐遵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間塔插,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工拓哟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留想许,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像流纹,于是被迫代替她去往敵國和親糜烹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345