内存分区
内存我们人为的把他分为5大区,栈区、堆区、全局区、常量区、代码区,地址从高到低
栈区
- 栈区存放函数的参数值、局部对象的值、对象的指针。由系统分配和释放。
- 线性结构,内存连续
如下图定义了两个整形、和一对象 a、b、object在栈中的存储结构
管理及优化方案:不要在栈区创建大量的局部变量,尤其是循环创建,可以使用autorealsepool自动释放池来及时释放和优化
堆区
- 通过alloc创建的对象,由开发者进行管理,
- 动态分配和释放,编译时不能提前确定
- 速度相对慢,操作灵活,内存不连续
举例如下图:定义了4个object对象
对象在堆中的存储结构:
全局静态区
- 全局区是编译时分配的内存空间,在程序运行过程中数据一直存在
- 全局区又分为未初始化bbs段和已初始化data段。
- 存储全局变量和静态变量(static修饰)
常量区
常量字符串就是放在这里的。程序结束后由系统释放。
代码区
存放函数体的二进制代码。
还有像内核区,是内核系统占用的内存,还保留了一块内存区
内存相关面试题
有一个person类实现如下:
调用如下方法:
问题一,第二次能否调用?
答案是,能调用。oc实例方法调用本质,实际上是通过isa找到类地址,然后通过类的methodsList去寻找方法.kc这个时候实际上指向了cls。
问题二,第二次打印是什么?
查看打印结果:
打印的居然是person对象,那么为什么呢。
- 首先第一次调用的时候self,是person对象。person对象通过偏移8个字节,拿到name属性。
self.name(地址) = person地址+8
- 那么同样第二次打印 我们分析栈的存储
同样self.name = cls的地址 +8
.也就是0x7ffee335f7d0+8 = 0x7ffee335f7d8
。刚好是person
的栈地址。所以最后打印的是person
。