OC对象NSObject在运行时会被转换成:
NSObject *obj = [[NSObject alloc] init];
|| 转换成
struct NSObject_IMPL {
Class isa;
}
一个NSObject对象在内存中其实是一个结构体,Class是一个指向结构体的指针(void *),32位操作系统下指针占用4个字节,64位下占用8个字节。
所以该结构体在内存中只需要8个字节就够了,但是由于系统分配内存对齐规则(小于16个字节,则分配16字节),所以该NSObject在alloc的时候实际占用16字节。
获取大小方法:
//获得NSObject类实例对象的大小 输出是8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
//获得obj指针指向的内存区域大小 输出是16
NSLog(@"zd%",malloc_size((__bridge const void *)obj));

自定义对象的研究:
@interface Student : NSObject {
int _num;
int _age;
}
@end
在内存中实际会被转换成:
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _num;
int _age;
}
该对象在内存中实际占用16字节,因为NSObject分配了16个字节空间,isa指针只占用8个字节,两个属性各占4个字节,所以系统无需再额外分配空间。

更复杂的继承结构
OC对象分类:
- instance对象 - 实例对象
- class对象 - 类对象
- meta-class - 元类对象
1.实例对象:
通过类alloc出来的
NSObject *obj = [[NSObject alloc] init];
实例对象在内存中存储的信息包括:
- isa指针
- 其他成员变量
2.类对象:

类对象是Class类型指针。
可通过实例对象得到:
NSObject *obj = [[NSObject alloc] init];
Class objClass1 = [obj class];
或者使用runtime方法:
NSObject *obj = [[NSObject alloc] init];
Class objClass2 = objcet_getClass(obj);
或者直接调用类方法:
Class objClass = [NSObject class];
每个类对象在内存中只存在一份,也就是上面的objClass1和objClass2是指向同一块内存。
类对象在内存中存储的信息包括:
- isa指针
- superClass指针
- 类的属性信息(property)。非属性值,因为属性值只存储在实例对象当中,这里存储的是属性类型等
- 类的对象方法信息(
- (void)method)。 - 类的协议信息(protocol)。
- 类的成员变量信息(ivar)。
- 等等...
3.元类对象:

跟类对象一样,也是Class指针类型,所以他们的内存结构是一样的。
只能通过类对象来获得:
Class objClass = [NSObject class];
//传入的必须是类对象,如果是实例对象,那么得到的是类对象,而不是元类对象
Class objMetaClass = object_getClass(objClass);
元类对象在内存中存储的信息包括:
- isa指针
- superClass指针
- 类的方法信息。(
+ (void)method) - 等等
isa指向:

isa指向
superClass指向:

superClass指向
总结:

- 实例对象的isa指向类对象
- 类对象的isa指向元类对象
- 元类对象的isa指向基类的元类,基类的元类isa指向自身
- 类对象的superClass指向父类的类对象
- 基类的类对象的supeClass指向nil
- 元类对象的supeClass指向父类的元类对象
- 基类的元类对象的supeClass指向的是基类的类对象
class和meta-class结构
Class类型在内存中实际是objc_class结构体:
