獲取內(nèi)存大小的三種方式
- sizeof
- class_getInstanceSize
- malloc_size
sizeof
- 1、
sizeof是一個(gè)操作符,不是函數(shù) - 2、我們一般用sizeof計(jì)算內(nèi)存大小時(shí),
傳入的是數(shù)據(jù)類型,這個(gè)在編譯器的編譯階段(即編譯時(shí))就會(huì)確定大小而不是在運(yùn)行時(shí)確定。 - 3、
sizeof最終得到的結(jié)果是該數(shù)據(jù)類型占用空間的大小
class_getInstanceSize
這個(gè)方法在iOS底層探究-03:alloc & init & new 源碼分析分析時(shí)就已經(jīng)分析了,是runtime提供的api,用于獲取類的實(shí)例對(duì)象所占用的內(nèi)存大小,并返回具體的字節(jié)數(shù),其本質(zhì)就是獲取實(shí)例對(duì)象中成員變量的內(nèi)存大小
malloc_size
這個(gè)函數(shù)是獲取系統(tǒng)實(shí)際分配的內(nèi)存大小
通過以下代碼驗(yàn)證一下:

以下是打印結(jié)果:

總結(jié)
-
sizeof:計(jì)算類型占用的內(nèi)存大小,其中可以放基本數(shù)據(jù)類型、對(duì)象、指針對(duì)于類似于
int這樣的基本數(shù)據(jù)而言,sizeof獲取的就是數(shù)據(jù)類型占用的內(nèi)存大小,不同的數(shù)據(jù)類型所占用的內(nèi)存大小是不一樣的而對(duì)于類似于NSObject定義的
實(shí)例對(duì)象而言,其對(duì)象類型的本質(zhì)就是一個(gè)結(jié)構(gòu)體(即 struct objc_object)的指針,所以sizeof(objc)打印的是對(duì)象objc的指針大小,我們知道一個(gè)指針的內(nèi)存大小是8,所以sizeof(objc) 打印是 8。注意:這里的8字節(jié)與isa指針一點(diǎn)關(guān)系都沒有?。。。?/p>對(duì)于
指針而言,sizeof打印的就是8,因?yàn)橐粋€(gè)指針的內(nèi)存大小是8
-
class_getInstanceSize:計(jì)算對(duì)象實(shí)際占用的內(nèi)存大小,這個(gè)需要依據(jù)類的屬性而變化,如果自定義類沒有自定義屬性,僅僅只是繼承自NSObject,則類的實(shí)例對(duì)象實(shí)際占用的內(nèi)存大小是8,可以簡單理解為8字節(jié)對(duì)齊 -
malloc_size:計(jì)算對(duì)象實(shí)際分配的內(nèi)存大小,這個(gè)是由系統(tǒng)完成的,可以從上面的打印結(jié)果看出,實(shí)際分配的和實(shí)際占用的內(nèi)存大小并不相等,這個(gè)問題可以通過iOS底層探究-03:alloc & init & new 源碼分析中的16字節(jié)對(duì)齊算法來解釋這個(gè)問題
結(jié)構(gòu)體內(nèi)存對(duì)齊
我們定義兩個(gè)結(jié)構(gòu)體,分別計(jì)算他們的內(nèi)存大小,以此來探究內(nèi)存對(duì)齊原理
struct Person {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
} person;
struct Bus {
double a; // 8
int b; // 4
char c; // 1
short d; // 2
} bus;
NSLog(@"%lu-%lu",sizeof(person),sizeof(bus));
以下是輸出結(jié)果:

從打印結(jié)果我們可以看出一個(gè)問題,兩個(gè)結(jié)構(gòu)體乍一看,沒什么區(qū)別,其中定義的變量 和 變量類型都是一致的,
唯一的區(qū)別只是在于定義變量的順序不一致,那為什么他們做占用的內(nèi)存大小不相等呢?其實(shí)這就是iOS中的內(nèi)存字節(jié)對(duì)齊現(xiàn)象
內(nèi)存對(duì)齊原則有以下三點(diǎn):
- 1:
數(shù)據(jù)成員對(duì)?規(guī)則:結(jié)構(gòu)(struct)或(聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從該成員大小或者成員的子成員大?。ㄖ灰摮蓡T有子成員,比如說是數(shù)組,結(jié)構(gòu)體等)的整數(shù)倍開始(比如int為4字節(jié)),則要從4的整數(shù)倍地址開始存儲(chǔ)。 - 2:
結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲(chǔ)。(struct a里存有struct b,b里有char,int ,double等元素,那b應(yīng)該從8的整數(shù)倍開始存儲(chǔ)) - 3:
結(jié)構(gòu)體的總大小:也就是sizeof的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補(bǔ)?。
驗(yàn)證對(duì)齊規(guī)則
下表是各種數(shù)據(jù)類型在ios中的占用內(nèi)存大小,根據(jù)對(duì)應(yīng)類型來計(jì)算結(jié)構(gòu)體中內(nèi)存大小

結(jié)構(gòu)體 Person 內(nèi)存大小計(jì)算
根據(jù)內(nèi)存對(duì)齊規(guī)則計(jì)算Person的內(nèi)存大小,詳解過程如下:
-
變量a:占8個(gè)字節(jié),從0開始,此時(shí)min(0,8),即0 -7 存儲(chǔ) a -
變量b:占1個(gè)字節(jié),從8開始,此時(shí)min(8,1),8可以整除1,即8 存儲(chǔ) b -
變量c:占4個(gè)字節(jié),從9開始,此時(shí)min(9,4),9不能整除4,繼續(xù)往后移動(dòng),直到min(12,4),12可以整除4,從12開始,即12 -15 存儲(chǔ) c -
變量d:占2個(gè)字節(jié),從16開始,此時(shí)min(16, 2),16可以整除2,即16 - 17 存儲(chǔ) d
因此Person的需要的內(nèi)存大小為18字節(jié),而Person中最大變量的字節(jié)數(shù)為8,所以 Person 實(shí)際的內(nèi)存大小必須是8 的整數(shù)倍,18向上取整到24,主要是因?yàn)?4是8的整數(shù)倍,所以sizeof(Person) 的結(jié)果是 24
結(jié)構(gòu)體 Bus 內(nèi)存大小計(jì)算
根據(jù)內(nèi)存對(duì)齊規(guī)則計(jì)算Bus的內(nèi)存大小,詳解過程如下:
-
變量a:占8個(gè)字節(jié),從0開始,此時(shí)min(0,8),即0 -7 存儲(chǔ) a -
變量b:占4個(gè)字節(jié),從8開始,此時(shí)min(8,4),8可以整除4,即8 -11 存儲(chǔ) b -
變量c:占1個(gè)字節(jié),從12開始,此時(shí)min(12,1),12可以整除1,即12 存儲(chǔ) c -
變量d:占2個(gè)字節(jié),從13開始,此時(shí)min(13, 2),13不能整除2,繼續(xù)往后移動(dòng),直到min(14,2),14可以整除2,從14開始,即14 - 15 存儲(chǔ) d
因此Bus的需要的內(nèi)存大小為16字節(jié),而Bus中最大變量的字節(jié)數(shù)為8,所以 Bus 實(shí)際的內(nèi)存大小必須是 8 的整數(shù)倍(就不需要向上取整),16剛好是8的整數(shù)倍,所以sizeof(Bus) 的結(jié)果是 16
結(jié)構(gòu)體嵌套結(jié)構(gòu)體
在定義一個(gè)結(jié)構(gòu)體PersonBus,在PersonBus中嵌套Bus,如下所示
struct PersonBus {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
struct Bus bus1;
} personBus;
NSLog(@"%lu-%lu",sizeof(personBus),sizeof(personBus.bus1));
打印結(jié)果如下:

分析 PersonBus 的內(nèi)存計(jì)算
-
變量a:占8個(gè)字節(jié),從0開始,此時(shí)min(0,8),即0 -7 存儲(chǔ) a -
變量b:占1個(gè)字節(jié),從8開始,此時(shí)min(8,1),8可以整除1,即8 存儲(chǔ) b -
變量c:占4個(gè)字節(jié),從9開始,此時(shí)min(9,4),9不能整除4,繼續(xù)往后移動(dòng),直到min(12,4),12可以整除4,從12開始,即12 -15 存儲(chǔ) c -
變量d:占2個(gè)字節(jié),從16開始,此時(shí)min(16, 2),16可以整除2,即16 - 17 存儲(chǔ) d -
結(jié)構(gòu)體成員bus1:bus1是一個(gè)結(jié)構(gòu)體,根據(jù)內(nèi)存對(duì)齊2:結(jié)構(gòu)體作為成員,結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍開始存儲(chǔ),而Bus中最大的成員大小為8,所以bus1要從8的整數(shù)倍開始,當(dāng)前是從18開始,所以不符合要求,需要往后移動(dòng)到24,24是8的整數(shù)倍,符合內(nèi)存對(duì)齊原則,所以24-39 存儲(chǔ) bus1
因此PersonBus的需要的內(nèi)存大小為40字節(jié),而PersonBus中最大變量為bus1, 其最大成員內(nèi)存字節(jié)數(shù)為8,根據(jù)內(nèi)存對(duì)齊原則,所以PersonBus實(shí)際的內(nèi)存大小必須是 8 的整數(shù)倍,40正好是8的整數(shù)倍,所以sizeof(PersonBus) 的結(jié)果是 40