@implementation MNSubclass
- (void)compareSelfWithSuperclass{
NSLog(@"self class = %@",[self class]);
NSLog(@"super class = %@",[super class]);
}
@end
复制代码
咱们平时编写的Objetcive-C,底层实现都是C/C++实现的 html
@interface MNPerson : NSObject
{
int _age;
double _height;
NSString *name;
}
复制代码
以MNPerson
为例,里面的成员变量有不一样类型是,好比int
、double
、NSString
类型,假如在C/C++ 中用数组
存储,显然是不太合理的ios
结构体
的数据格式,表示oc对象。// 转成c/c++ 代码后,MNPerson 的结构以下
struct NSObject_IMPL {
Class isa;
};
struct MNPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
double _height;
NSString *name;
};
复制代码
使用指令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc oc源文件 -o 输出的c++文件
将oc
代码转成c++
代码以后,发现内部确实是结构体c++
一个NSObject 对象,占用多少内存git
思路:github
NSObject
的本质是结构体,经过NSObject.m
能够发现,NSObject
只有一个 isa
成员,isa
的本质是 class
, struct objc_object *
类型,因此应该占据 8 字节NSLog(@"%zu",class_getInstanceSize([NSObject class]));
输出 - size = 8注意!实际上,面试
{
//得到 - NSObject 一个实例对象的成员变量所占用的大小 >> 8
NSLog(@"%zu",class_getInstanceSize([NSObject class]));
NSObject *obj = [[NSObject alloc]init];
// 获取 obj 指针,指向的内存大小 >> 16
NSLog(@"%zu",malloc_size((__bridge const void *)obj));
}
复制代码
//基于 `objc-class.m` 文件 750 版本
size_t class_getInstanceSize(Class cls)
{
if (!cls) return 0;
return cls->alignedInstanceSize();
}
// Class‘s ivar size rounded up to a pointer-size boundary.
// 点击一下 - 智能翻译 ==> (返回类的成员变量所占据的大小)
uint32_t alignedInstanceSize()
{
return word_align(unalignedInstanceSize());
}
复制代码
alloc init
, 查找alloc底层实现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;
}
复制代码
CoreFoundation
硬性规定,一个对象,至少有 16 字节- 以
NSObject
为例,这里传入的size
是alignedInstanceSize
, 而alignedInstanceSize
已经知道 = 8, 8 < 16,retun 16, 最终 NSObject 建立的对象,占据的内存大小是 16
memory read
查看对象内存(lldb) p obj
(NSObject *) $0 = 0x000060000000eb90
(lldb) memory read 0x000060000000eb90
0x60000000eb90: a8 6e 3a 0b 01 00 00 00 00 00 00 00 00 00 00 00
复制代码
也能发现,前8 位存储 isa
指针,后 8 位都是0,可是整个对象仍是占据了 16 个字节bash
NSObject
对象(malloc_size
函数得到)NSObject
只使用了 8个字节的存储空间(64bit系统下)class_getInstanceSize()
@interface MNStudent : NSObject
{
int _age;
int _no;
}
@end
复制代码
NSObject
占据16个字节可知,base = 16哈哈!中计了!数据结构
原理解释:app
- 以前
NSObject
建立一个对象,确实是分配了 16 个字节的空间- 可是,他还有未使用的空间8个字节,仍是能够存储的
- 这里的
age
&&no
存进去,正好16
,以前分配的空间正好够用!因此答案是 16!
(大哥别打了,此次保证不挖坑了,别打,疼,别打脸别打脸。。。)
@interface MNPerson : NSObject
{
int _age;
int _height;
NSString *name;
}
复制代码
MNPerson
对象,占用多少内存isa
= 8, int age
= 4, int height
= 4, NSString
= char * = 8哈哈哈哈! 又中计了!
这时候你确定好奇了
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
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;
}
复制代码
extraBytes
通常都是 0,这里能够理解为size = alignedInstanceSize()
;alignedInstanceSize = class_getInstanceSize
,class_getInstanceSize
由上图的log信息也能够知道 =24
- 心里os: who tm fucking 32?
下载`libmalloc`,找到`calloc`的实现
void *
calloc(size_t num_items, size_t size)
{
void *retval;
retval = malloc_zone_calloc(default_zone, num_items, size);
if (retval == NULL) {
errno = ENOMEM;
}
return retval;
}
发现这个函数,就是咱们调用的`calloc`函数的底层
void *
malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);
void *ptr;
if (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {
internal_check();
}
ptr = zone->calloc(zone, num_items, size);
if (malloc_logger) {
malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,
(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);
}
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_END, (uintptr_t)zone, num_items, size, (uintptr_t)ptr);
return ptr;
}
复制代码
心里os: exo me? 这传入的 size_t size = 24
,怎么返回32的??
检索Buckets
- (libmalloc 源码)
#define NANO_MAX_SIZE 256
/* Buckets sized {16, 32, 48, ..., 256} */
复制代码
- 发现,iOS 系统分配的时候,有本身的分配规则, 不是说你须要的size多大,就建立多大
- 操做系统内部有本身的一套规则,这里的都是 16 的倍数,而操做系统在此基础之上,操做系统的操做访问最快
- 因此,在
MNPerson
对象须要 24 的size的时候,操做系统根据他的规则,直接建立了 32 的size的空间,因此这里的答案是 32!
补充说明: sizeof
运算符
(lldb) po [obj class]
MNPerson
(lldb) po sizeof(obj)
8
(lldb) po sizeof(int)
4
复制代码
sizeof
是运算符,不是函数,编译时即知道,不是函数- 这里的
obj
是对象, *obj - 指针指向,编译器知道他是指针类型,因此 sizeof = 8(指针占据8个字节) - 特别注意,这里传入的不是对象!是指针sizeof
是告诉你传入的类型,占多少存储空间
alloc
出来的对象alloc
都会产生新的instance
对象(内存不相同)instance
对象存储的信息
class
对象class
对象在内存中存储的信息
Class metaClass = object_getClass([NSObject class]);
metaclss
是 NSObject
的meta-class
对象meta-class
在内存中只有一份,每一个类都有且只有一个 meta-class
对象meta-class
也是类,与class
的对象结构同样,可是内部的数据不同(用途不一样)meta-clas
包括:
提问:object_getClass
与 objc_getClass
的区别
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
复制代码
instance
对象,返回 class
class
, 返回的是 meta-class
对象meta-class
,返回的是 root-meta-class
对象 Class objc_getClass(const char *aClassName)
{
if (!aClassName) return Nil;
// NO unconnected, YES class handler
return look_up_class(aClassName, NO, YES);
}
复制代码
(图片来自于 www.sealiesoftware.com/blog/archiv…)
看懂这张图 - 就等价于看懂
isa
&&superclass
了
探究流程:
@interface MNSuperclass : NSObject
- (void)superclassInstanceMethod;
+ (void)superClassMethod;
@end
@implementation MNSuperclass
- (void)superclassInstanceMethod{
NSLog(@"superclass-InstanceMethod - %p",self);
}
+ (void)superClassMethod{
NSLog(@"+ superClass-classMethod- %p",self);
}
@end
@interface MNSubclass : MNSuperclass
- (void)subclassInstanceMethod;
@end
@implementation MNSubclass
- (void)subclassInstanceMethod{
NSLog(@"subclassInstanceMethod- %p",self);
}
@end
复制代码
MNSubclass *subclass = [[MNSubclass alloc]init];
[subclass superclassInstanceMethod];
复制代码
subclass
调用对象方法,对象方法存在 class
中subclass
对象,经过 isa
指针,找到其对应的 MNSubclass
类MNSubclass
是否有 superclassInstanceMethod
方法的实现,发现没有,MNSubclass
沿着 superclass
指针找到他的父类 - MNSuperclass
MNSuperclass
中找到 superclassInstanceMethod
的实现,调用它,整个流程结束[MNSubclass superClassMethod];
meta-class
中MNSubclass
,沿着isa
指针,找到其对应的meta-class
MNSubclass
的 meta-class
中是否有 superClassMethod
方法的实现,发现没有,沿着 superclass
指针找到 MNSuperclass
的 meta-class
MNSuperclass
的 meta-class
有superClassMethod
方法实现,调用,流程结束meta-class
对象存储的是类方法,class
存储的是 对象方法Root class
就是 NSObject
, 要给 NSObject
添加方法就要用到 分类
NSObject
的对象方法是否会被调用//"NSObject+MNTest"类的声明 && 实现
@interface NSObject (MNTest)
+ (void)checkSuperclass;
@end
@implementation NSObject (MNTest)
+ (void)checkSuperclass{
NSLog(@"+NSObject checkSuperclass - %p",self);
}
@end
//main函数中调用
int main(int argc, char * argv[]) {
@autoreleasepool
{
[MNSubclass checkSuperclass];
NSLog(@"MNSubclass = %p",[MNSubclass class]);
}
return 0;
}
--------------------------------------------------------
控制台输出:
+NSObject checkSuperclass - 0x105817040
InterView-obj-isa-class[36303:7016608] MNSubclass = 0x105817040
复制代码
- 发现,调用
checkSuperclass
类方法的,是MNSubclass
类- 这时候要验证上面那条
meta-class
指向root-class
的线, 这里的root-class
即等于NSObject
root-class
中只存对象方法,这里,只要验证,NSObject
中同名的类方法实现取消,变成同名的对象方法测试,便可得出结论- 声明的仍是
+ (void)checkSuperclass
,实现的方法用- (void)checkSuperclass
对象方法替换
@interface NSObject (MNTest)
+ (void)checkSuperclass;
@end
@implementation NSObject (MNTest)
//+ (void)checkSuperclass{
// NSLog(@"+NSObject checkSuperclass - %p",self);
//}
- (void)checkSuperclass{
NSLog(@"-NSObject checkSuperclass - %p",self);
}
@end
//main函数中调用
int main(int argc, char * argv[]) {
@autoreleasepool
{
[MNSubclass checkSuperclass];
NSLog(@"MNSubclass = %p",[MNSubclass class]);
}
return 0;
}
--------------------------------------------------------
控制台输出:
-NSObject checkSuperclass - 0x101239040
InterView-obj-isa-class[36391:7022301] MNSubclass = 0x101239040
复制代码
发现 - 调用的仍是类方法 + (void)checkSuperclass
,可是最终实现的,倒是对象方法 - (void)checkSuperclass
[MNSubclass checkSuperclass]
其实本质上,调用的是发送消息方法,函数相似是objc_msgsend([MNSubclass class], @selector(checkSuperclass))
@selector(checkSuperclass)
并未说明是 类方法 or 对象方法root-meta-class
经过super class
找到了root-class
(NSObject),NSObject
类不是元类,存储的是对象方法,因此 最终调用了NSObject -checkSuperclass
这个对象方法@implementation MNSubclass
- (void)compareSelfWithSuperclass{
NSLog(@"self class = %@",[self class]);
NSLog(@"super class = %@",[super class]);
}
@end
----------------------------------------
调用:
MNSubclass *subclass = [[MNSubclass alloc]init];
[subclass compareSelfWithSuperclass];
复制代码
问: [self class]
&& [super class]
分别输出什么
思路:
class
方法 是NSObject
的一个对象方法,对方方法存在 class
中subclass
对象,经过 isa
指针,找到其对应的 MNSubclass
类MNSubclass
是否有 class
方法的实现,发现没有,MNSubclass
沿着 superclass
指针找到他的父类 - MNSuperclass
MNSuperclass
中是否有 class
方法的实现,发现没有,MNSuperclass
沿着 superclass
指针找到他的父类 - NSObject
NSObject
中找到 class
的实现MNSubclass
NSLog(@"self class = %@",[self class]);
NSLog(@"super class = %@",[super class]);
----------------------------------------------------------------------
控制台输出:
InterView-obj-isa-class[36796:7048007] self class = MNSubclass
InterView-obj-isa-class[36796:7048007] super class = MNSubclass
复制代码
感谢小码哥 的精彩演出,文章中若是有说错的地方,欢迎提出,一块儿学习~
欢迎点赞fork~
友情客串: