本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢。
1. 一个NSObject对象占用多少内存 ?
答:系统分配了16个字节给NSObject对象(通过malloc_size函数获得),但NSObject对象内部值使用了8个字节的空间(64位环境下,可以通过class_getInstenceSize函数获得)
2. 如果一个实例对象有自定义成员变量或属性;又或者有父类;又或者有自定义方法、协议;这个时候占多大内存空间呢 ?
这其中涉及到了结构体成员变量的内存对齐的问题,结构体内存对齐其中有一条要求结构体大小需要是最大成员变量大小的整数倍,而最大成员变量是指针变量(8个字节),结构体的最终的大小需要是8的整数倍。系统实际分配的大小也是16字节,所以分配的内存会是16的整数倍。详细了解可以参考iOS底层原理(一):OC对象实际占用内存与开辟内存关系。至于自定义方法、协议是不存储在实例对象的内存中的,而是放在类对象的方法列表中。(原因是方法只需要存储一次就可以了,不管初始化多少个实例对象,但只要都是同一个类初始化出来的都需要相同的方法,这样看来放在类对象存储是很合理的)。
注意
不同的数据类型所分配的内存大小是不同的,比如一个指针分配的空间是8个字节,一个基本数据类型分配的空间是4个字节。下面提供一张一览表:
3. 对象isa指针指向哪里?
<1> instance(实例)对象的isa指向其class对象;
<2> class对象的isa指针指向meta-class(元类)对象
<3> meta-class(元类)对象的isa指针指向基类(一般是指NSObject)的meta-class对象
但是被KVO监听的对象除外,因为KVO监听会在运行时生成新的派生类。isa指针指向的是这个派生类。
4 . isa 指针变量中存储了什么 ?superclass呢 ?
在arm64架构之前,存储了ISA指针指向对象的内存地址,但是在arm64之后需要在存储地址值加上ISA_MASK 这个值才是指向对象的内存地址。示意图如下
跟isa不同,superclass指针是直接指向父类的类对象,superclass指针中存储的内容就是父类的类对象的地址值。
5. 为什么几乎所有的实例对象都有一个isa指针 ?
简单回答:OC 实例对象基本上都继承自NSObject,而NSObject自带就有一个成员变量isa . 所以实例对象基本上都有这个isa 指针。
有深度的回答:OC 实例对象基本上都继承自NSObject,而NSObject自带就有一个成员变量isa . 另外isa是用来指向实例对象的类对象、类对象的元类对象的,通过isa可以找到相关的方法、协议进行调用,这在OC运行时通过object_getClass()方法,传入对象的isa指针来查找对象(查找实例对象的类对象,查找类对象的元类对象,查找元类对象返回基类的元类对象)。都需要用到的一个重要的指针变量,所以所有继承自NSObject的实例对象都有一个isa指针变量。
总结:
1.Class objc_getClass(const char *aClassName)
1> 传入字符串类名
2> 返回对应的类对象
2.Class object_getClass(id obj)
1> 传入的obj可能是instance对象、class对象、meta-class对象
2> 返回值
a) 如果是instance对象,返回class对象
b) 如果是class对象,返回meta-class对象
c) 如果是meta-class对象,返回NSObject(基类)的meta-class对象
3.- (Class)class、+ (Class)class
1> 返回的就是类对象
- (Class)class { return self->isa;}
+ (Class)class { return self; }
6. isa 指针是否绝对安全 ?
isa 指针不是绝对安全的。
原因:isa指针是用来查找实例对象的类对象,类对象的元类对象;如果在运行时修改其isa指针指向一个不相关的类或元类此时就不在安全
7. OC 对象的信息存放哪里 ?
<1> 成员变量的具体值存放在实例(instance)对象中.
<2> 对象方法、属性、成员变量、协议信息都是存放在类(class)对象中的.
<3> 类方法存放在元类(meta-class)对象中.
8. 一个实例对象调用copy方法,返回的是同一对象吗 ?
可能是同一个对象也可能不是,这取决与被拷贝的对象是什么类型;如对可变数组拷贝,生成不可变数组,这时很明显生成了新的对象是深拷贝当然就不是同一个对象!再或者某个对象实现了copyWithZone方法并且返回了通过alloc、new方法创建的对象那也是不同对象!
9. OC 对象内存分配的注意点或特点是什么 ?
OC对象的本质是结构体,结构体在分配内存时是以16个字节为单位在堆空间分配存储空间的;在这个过程中是以内存对齐为原则进行内分配。
比如一个实例对象的成员变量总共需要28字节的存储空间那么系统就会分配32个字节的内存给它。