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占用多少内存?