文章目錄
- 前言
- 獲取內存大小的三種常用方式
- sizeof
- class_getInstanceSize
- malloc_size
- 總結
前言
??之前學習alloc相關源碼,涉及到內存對齊的相關內容,今天筆者詳細學習了一下相關內容并寫了此篇博客。
獲取內存大小的三種常用方式
??獲取內存大小的方式有很多種,主要分為三類:獲取對象實例占用的內存大小、獲取進程占用的內存大小??、獲取數據結構/內存塊的大小?。在iOS中獲取內存大小的三種方式主要有:sizeof 、class_getInstanceSize 、malloc_size。
sizeof
- 編譯時運算符??,返回變量或類型在內存中占用的字節數。
- ??只適用于??基本數據類型(int、float)、結構體、類實例(僅計算靜態分配的內存)。
- 不適用于動態分配的內存(如通過 malloc 分配的部分)、對象頭(如 Objective-C 的 isa 指針)。
??首先,需要明確,sizeof是一個操作數,不是函數;其次,這個大小在編譯時就已經確定了,不考慮運行時的動態內存。對于OC對象,sizeof只返回指針的大小(通常情況下為8字節),而不是對象的實際占用內存。
%zu:
一般用于輸出或讀取 size_t 類型(即無符號整型)的變量(通常是 sizeof 運算符的結果)。
class_getInstanceSize
- Objective-C 運行時函數??,返回一個 Objective-C 類的實例對象在內存中占用的實際大小(不包括額外的 malloc 分配開銷)。
- ??包含的內容:isa 指針(8 字節),所有實例變量(ivars)的大小,內存對齊填充。
#import <objc/runtime.h>@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name; // 8 字節
@property (nonatomic, assign) NSInteger age; // 8 字節
@end@implementation MyClass
@end// 計算實例變量總大小
size_t instanceSize = class_getInstanceSize([MyClass class]);
NSLog(@"實例變量大小: %zu 字節", instanceSize);
按理論來說,這里應該輸出16個字節,但實際上輸出為24個字節,這是為什么呢?
這里可以簡單理解為class_getInstanceSize 遵循的是8字節對齊:
每個 Objective-C 對象都有一個 isa 指針,指向它的類對象,這在 64 位系統上占用 8 字節。
在剛剛的代碼中:
NSString *name:一個強引用的指針,占用 8 字節
NSInteger age:在 64 位系統上占用 8 字節
所以剛才代碼中的內存計算:isa (8) + name (8) + age (8) = 24 字節
所以總和是 24 字節(8 + 8 + 8),這正好是 8 字節對齊的倍數,不需要額外填充。如果這個類沒有聲明任何實例變量,大小會是 16 字節(8 字節的 isa 指針 + 8 字節的填充,以滿足最小 16 字節的對象大小要求)。
至于為什么類沒有聲明任何實例變量,大小會是 16 字節:
isa 指針占用 8 字節(所有 Objective-C 對象都有)。
Objective-C 運行時強制對象最小大小為 16 字節(即使沒有實例變量),這是為了內存管理的效率(減少小對象的內存碎片)。剩余的 8 字節是 填充(padding),未被使用但必須分配。
總結:
class_getInstanceSize遵循8字節對齊。
24 字節 是 isa + name + age 的自然大小,不需要額外填充。
類沒有聲明任何實例變量,大小會是 16 字節。
malloc_size
- ??C 標準庫函數??,返回 malloc(或 calloc/realloc)實際分配的內存塊大小(可能比請求的大小更大),遵循16字節對齊。
- 包含??對象本身的大小(class_getInstanceSize 的結果)和 malloc 的內存管理開銷(如內存對齊、內存池優化等)。
int *array = malloc(10 * sizeof(int)); // 請求40字節
size_t allocatedSize = malloc_size(array);
printf("Malloc size: %zu\n", allocatedSize); // 輸出為48(16字節對齊)
了解到這里,我們就可以把 class_getInstanceSize和malloc_size拉在一起看看,我們在剛剛 class_getInstanceSize學習的代碼里添加:
size_t allocatedSize = malloc_size((__bridge const void *)obj);
NSLog(@"malloc_size: %zu", allocatedSize); // 32
這里會輸出32,因為class_getInstanceSize 計算的是 24 字節,但 malloc 會 向上取整到最近的 16/32 字節,所以實際分配 32 字節:
總結
??先用代碼來進行對比,我們可以看到輸出結果:
??對三者進行總結如下: