objectiveC 的本質是什麼?c++
能容納多種類型的結構是啥?面試
一個對象佔多少字節objective-c
一個OC對象在內存中是如何佈局的?佈局
衆所周知,OC 是 c ,c++ 的集合。到到下一層都會變成c,c++ 代碼的樣式。ui
結構體,結構體可以容納不少類型的數據。spa
咱們經過 clang -rewrite-objc main.m -o mian.cpp 看一下指針
main.m 的 codecode
LBPerson *person = [[LBPerson alloc] init];
NSLog(@"%zd",class_getInstanceSize([person class])); // 8
NSLog(@"%zd", malloc_size((__bridge const void *)person)); // 16
複製代碼
打印出來的結果分別是orm
爲何是這樣的呢?其實這裏涉及到c,c++ 寫的objc 代碼邏輯8字節對齊,以及malloc的策略,malloc 的策略是 16 字節對齊。那麼分配了內存16字節,只用了8字節,多了八字節。那麼已經用掉的八字節 以及 多出來的八字節分別是幹什麼用的呢?咱們埋下一個伏筆。咱們繼續看對象的本質是什麼?cdn
我在clang 事後的代碼裏面找到了這麼一段代碼:
恍然大悟,這是一個結構體那麼 NSObject_IMPL 是啥呢?我又找到了這段代碼。
✌️,咱們發現結構體裏面嵌套了一個結構體,那麼咱們大概清楚了,對象就是這麼一個結構體。我繼續看 Class isa:
那麼 Class 是什麼呢?
咱們回到main.m當中,點擊NSObject 進入:
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
複製代碼
那麼objc_class 又是什麼呢?我找到蘋果開源的代碼,發現是一個結構體,objc_object
發現 objc_object 也是一個結構體。那麼知道了,Class 是結構體指針。由此咱們知道了,一個對象的第一個屬性是一個isa,isa 是一個結構體指針。而結構體的第一個成員是isa_t。那麼指針指向對象的首地址就是isa_t 的首地址。一個指針的大小是8個字節。那麼咱們的最後一個問題也迎刃而解了,內存分佈結構體也差很少知道了。
可是還有一個問題,這個對象的大小到底是多少呢?這就要看怎麼問了,若是說一不二個對象的實際大小,那麼就是8,若是說是一個對象分配的內存空間,那麼就是至少16 。咱們其實上面的class_getinstanceSize 是求的實際用了多大的空間。沒有用掉的空間實際上也是這個對象的所擁有空間。通常我會回答 是16 字節。
咱們來具體看一下代碼咱們就清楚爲何了。
蘋果開源代碼中有這麼一段代碼:
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
if (!cls) return nil;
assert(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
// 這裏就是得到空間大小的代碼
size_t size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (!zone && fast) {
obj = (id)calloc(1, size); // 建立空間
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor); // 存儲數據
}
else {
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
if (!obj) return nil;
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (cxxConstruct && hasCxxCtor) {
obj = _objc_constructOrFree(obj, cls);
}
return obj;
}
複製代碼
第一個初始化
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes; // 這裏實際上是字節對齊,我會在下一節進行分析。
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
複製代碼
咱們也從側面驗證了一個對象若是沒有進行屬性分配**,會分配16 字節的大小。儘管,空間不會所有用完 。**
size_t class_getInstanceSize(Class cls)
{
if (!cls) return 0;
return cls->alignedInstanceSize();
}
複製代碼
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
複製代碼
咱們能夠看到,其實最終調用的都是 字節對齊對應的大小。
知識點補充:
關於這裏 涉及到 class_data_bits_t 裏面的 class_rw_t -> class_ro_t 。之後分析。
一個NSObject佔用多少內存?