《跟我學》之OC內(nèi)存對齊原理

1. 內(nèi)存對齊原理

上一篇提到了對象在alloc創(chuàng)建時內(nèi)存分配情況裹纳,
這一篇我們來更加深入的來研究一下什么叫內(nèi)存對齊

1.1 準備工作

話不多說,為了方便直觀的體現(xiàn)差異紧武,定義一個宏剃氧,打印對象的 isa、內(nèi)存地址阻星、對象類型占用的內(nèi)存大小朋鞍、對象實際占用的內(nèi)存大小對象實際分配的內(nèi)存大小妥箕。一定要注意占用跟實際分配的區(qū)別滥酥,是不一樣的。等一下看日志就一目了然畦幢。
照舊萬年祖?zhèn)饔^察對象日志代碼

#define Log(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p || 對象類型占用的內(nèi)存大小%lu, 對象實際占用的內(nèi)存大小%lu, 對象實際分配的內(nèi)存大小%lu ", name, [_var class], &_var, sizeof(_var), class_getInstanceSize([_var class]) ,malloc_size((__bridge const void*)(_var))); })

1.2 對象

昨天我們研究了人Person類坎吻。今天不研究人,研究Dog狗類??并且附上源代碼已經(jīng)運行結果日志

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

@interface Dog : NSObject
@end

@implementation Dog
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog *dog = [Dog alloc];
        Log(dog);
        /*
         * dog: Dog -> 0x7ffeefbff588 || 對象類型占用的內(nèi)存大小8, 對象實際占用的內(nèi)存大小8, 對象實際分配的內(nèi)存大小16
         */
    }
    return 0;
}

我們這個無屬性dog對象實際分配的內(nèi)存大小16跟我昨天說的一樣沒有騙大家宇葱。這一點可以放心瘦真。因為是無屬性對象實例刊头,該對象只有isa指針所以只占用了8個大小的內(nèi)存空間。

@property (nonatomic, strong) NSString *name;
如果我們給這個對象定義一個屬性時打印如下

對象類型占用的內(nèi)存大小8, 對象實際占用的內(nèi)存大小16, 對象實際分配的內(nèi)存大小16

@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) int age;
如果我們給這個對象定義兩個屬性時打印如下

對象類型占用的內(nèi)存大小8, 對象實際占用的內(nèi)存大小24, 對象實際分配的內(nèi)存大小32

@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) int height;
如果我們給這個對象定義三個屬性時打印如下

對象類型占用的內(nèi)存大小8, 對象實際占用的內(nèi)存大小24, 對象實際分配的內(nèi)存大小32

我們發(fā)現(xiàn)隨著屬性的增加實際的分配內(nèi)存大小符合昨天我們研究的對象創(chuàng)建16字節(jié)對齊原則诸尽。
對象類型占用的內(nèi)存大小始終為8我猜測是對象指針的占用大小
對象實際占用的內(nèi)存大小屬性以8字節(jié)對齊排列
我們來給dog屬性賦值之后

Dog *dog = [Dog alloc];
dog.name = @"旺財";
dog.age = 2;
dog.height = 80;

x/4gx dog一下看一下內(nèi)存情況

0x104007b50: 0x001d800100002315 0x0000000200000001
0x104007b60: 0x0000000100001018 0x0000000000000000
圖1

我們發(fā)現(xiàn) 0x0000000100001018是設置的name原杂, 0x0000005000000002居然po不出來。
我們嘗試po 0x00000050height弦讽,po 0x00000002age。原來heightage共用了內(nèi)存段節(jié)約內(nèi)存

1.3結論

以上這個例子來進行說明 蘋果中屬性重排膀哲,即內(nèi)存優(yōu)化因為age跟height各占用8比較浪費往产。雖然分配了32。但是一共占用24某宪。跟你定義屬性的順序無關仿村。最終會按著最優(yōu)的方式重新排列

2 結構體

對象研究完了兴喂。我們再來看一下結構體,看一下通過結構體的方式是否能驗證些什么畏鼓?

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

struct Dog2{
    double b;   //8字節(jié)
    int c;      //4字節(jié)
    short d;    //2字節(jié)
    char a;     //1字節(jié)
}Dog2;
NSLog(@"狗一大小%lu--狗二大小%lu",sizeof(Dog1), sizeof(Dog2));
/*狗一大小24--狗二大小16*/

我們發(fā)現(xiàn)同是 4 個屬性云矫,同樣包含char,double,int,short4個類型汗菜,只是順序不同罷了。最后大小缺不一樣
莫非就是我們之前說的內(nèi)存對齊?只是對象不需要你手動排列巡揍。而結構體需要你手動排列才生效腮敌,那么它的規(guī)則是什么呢俏扩?

內(nèi)存對齊規(guī)則

一般內(nèi)存對齊的原則主要有以下三點
1、數(shù)據(jù)成員的對齊規(guī)則可以理解為min(m, n) 的公式, 其中 m表示當前成員的開始位置, n表示當前成員所需要的位數(shù)啤斗。如果滿足條件 m 整除 n (即 m % n == 0), n 從 m 位置開始存儲, 反之繼續(xù)檢查 m + 1 能否整除n, 直到可以整除, 從而就確定了當前成員的開始位置钮莲。
2、結構體作為成員:如果一個結構里有某些結構體成員,則結構體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲.(struct a里存有struct b,b里有char,int ,double等元素,那b應該從8的整數(shù)倍開始存儲.)
3崔拥、結構體的總大小,也就是sizeof的結果,.必須是其內(nèi)部最大成員的整數(shù)倍.不足的要補?

我們通過簡單的計算來驗證一下

結構體Dog1 內(nèi)存大小計算
根據(jù)內(nèi)存對齊規(guī)則計算Dog1的內(nèi)存大小链瓦,詳解過程如下:

變量 a :占 1 個字節(jié),從0開始渤刃,此時 min(0, 1)卖子,即 0 存儲 a
變量 b :占 8 個字節(jié)刑峡,從1開始,此時 min(1, 8)诫舅, 1 不能整除 8 宫患,繼續(xù)往后移動,知道 min(8, 8)俏讹,從 8 開始泽疆,即 8-15 存儲 b
變量 c :占4個字節(jié)玲献,從16開始,此時min(16, 4)瓢娜,16 可以整除 4 眠砾,即 16-19 存儲 c
變量 d :占2個字節(jié)托酸,從20開始柒巫,此時min(20, 2)堡掏,20 可以整除 2 刨疼,即 20-21 存儲 d
因此 Dog1 的需要的內(nèi)存大小為 15 字節(jié),而 Dog1 中最大變量的字節(jié)數(shù)為 8 亭畜,所以 Dog1 實際的內(nèi)存大小必須是 8 的整數(shù)倍贱案,18 向上取整到 24止吐,主要是因為 248 的整數(shù)倍侨糟,所以 sizeof(Dog1) 的結果是 24

結構體 Dog2 內(nèi)存大小計算
根據(jù)內(nèi)存對齊規(guī)則計算 Dog2 的內(nèi)存大小秕重,詳解過程如下:

變量 b :占 8 個字節(jié),從 0 開始二拐,此時 min(0, 8) 凳兵,即 0-7 存儲 b
變量 c :占 4 個字節(jié)庐扫,從 8 開始,此時 min(8, 4) 铅辞, 8 可以整除 4 ,即 8-11 存儲 c
變量 d :占 2 個字節(jié)斟珊,從 12 開始倍宾,此時 min(12, 2)20 可以整除2高职,即 12-13 存儲 d
變量 a :占 1 個字節(jié),從 14 開始寥粹,此時 min(14, 1) 埃元,即 14 存儲 a
因此Dog2的需要的內(nèi)存大小為 15字節(jié),而 Dog2 中最大變量的字節(jié)數(shù)為 8阔拳,所以 Dog2 實際的內(nèi)存大小必須是 8 的整數(shù)倍类嗤, 15 向上取整到 16 ,主要是因為 168 的整數(shù)倍货裹,所以 sizeof(Dog2) 的結果是 16

不知道誰最大弧圆?我們來先看一個表笔咽,下表是對不同數(shù)據(jù)類型所占用的內(nèi)存大小(純手打,可復制)
有需要的點個關注叶组。評論查眼??Mark扶叉,老司機開車從此不迷路

C OC 32位 64位
bool BOOL(64位) 1 1
signed char (__signed char)int8_t、BOOL(32位) 1 1
unsigned char Boolean 1 1
short int16_t 2 2
unsigned short unichar 2 2
int int32_t boolean_t(32位)溢十、NSInteger(32位) 4 4
unsigned int boolean_t(64位)达吞、NSUInteger(32位) 4 4
long NSInteger(64位) 4 8
unsigned long NSUInteger(64位) 4 8
long long int64_t 8 8
float CGFloat(32位) 4 4
double CGFloat(64位) 8 8
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吞鸭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子遮咖,更是在濱河造成了極大的恐慌造虏,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陶珠,死亡現(xiàn)場離奇詭異揍诽,居然都是意外死亡栗竖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門饵筑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來处坪,“玉大人架专,你說我怎么就攤上這事〔拷牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锡移。 經(jīng)常有香客問我,道長淆珊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任擂找,我火速辦了婚禮浩销,結果婚禮上,老公的妹妹穿的比我還像新娘慢洋。我一直安慰自己且警,他們只是感情好,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布肩刃。 她就那樣靜靜地躺著杏头,像睡著了一般醇王。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寓娩,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天寞埠,我揣著相機與錄音焊夸,去河邊找鬼。 笑死阱穗,一個胖子當著我的面吹牛揪阶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扰魂,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姐直!你這毒婦竟也來了声畏?” 一聲冷哼從身側響起姻成,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤科展,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后徘跪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琅攘,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡哨查,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年寒亥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片护盈。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡羞酗,死狀恐怖檀轨,靈堂內(nèi)的尸體忽然破棺而出欺嗤,到底是詐尸還是另有隱情煎饼,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布筒溃,位于F島的核電站怜奖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏歪玲。R本人自食惡果不足惜滥崩,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一钙皮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧崇摄,春花似錦慌烧、人聲如沸屹蚊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汹粤。三九已至命斧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘱兼,已是汗流浹背国葬。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芹壕,地道東北人汇四。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像踢涌,于是被迫代替她去往敵國和親通孽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355