iOS 内存管理(内存布局)

1,568 阅读2分钟

内存分区

内存我们人为的把他分为5大区,栈区、堆区、全局区、常量区、代码区,地址从高到低

内存布局.png

栈区

  • 栈区存放函数的参数值、局部对象的值、对象的指针。由系统分配和释放。
  • 线性结构,内存连续

如下图定义了两个整形、和一对象 截屏2021-09-19 上午9.43.57.png a、b、object在栈中的存储结构

截屏2021-09-19 上午9.48.13.png

管理及优化方案:不要在栈区创建大量的局部变量,尤其是循环创建,可以使用autorealsepool自动释放池来及时释放和优化

堆区

  • 通过alloc创建的对象,由开发者进行管理,
  • 动态分配和释放,编译时不能提前确定
  • 速度相对慢,操作灵活,内存不连续

举例如下图:定义了4个object对象

截屏2021-09-19 上午10.06.01.png 对象在堆中的存储结构:

截屏2021-09-19 上午10.19.47.png

全局静态区

  • 全局区是编译时分配的内存空间,在程序运行过程中数据一直存在
  • 全局区又分为未初始化bbs段和已初始化data段。
  • 存储全局变量和静态变量(static修饰)

截屏2021-09-19 上午11.00.04.png

常量区

常量字符串就是放在这里的。程序结束后由系统释放。

截屏2021-09-19 上午11.07.58.png

代码区

存放函数体的二进制代码。

还有像内核区,是内核系统占用的内存,还保留了一块内存区

内存相关面试题

有一个person类实现如下:

截屏2021-09-19 下午3.09.45.png

截屏2021-09-19 下午3.09.50.png 调用如下方法:

截屏2021-09-19 下午3.11.43.png 问题一,第二次能否调用?

答案是,能调用。oc实例方法调用本质,实际上是通过isa找到类地址,然后通过类的methodsList去寻找方法.kc这个时候实际上指向了cls。

问题二,第二次打印是什么?

查看打印结果:

截屏2021-09-19 下午3.29.12.png

打印的居然是person对象,那么为什么呢。

  • 首先第一次调用的时候self,是person对象。person对象通过偏移8个字节,拿到name属性。

截屏2021-09-19 下午3.36.07.png

self.name(地址) = person地址+8

  • 那么同样第二次打印 我们分析栈的存储 截屏2021-09-19 下午3.43.41.png

同样self.name = cls的地址 +8.也就是0x7ffee335f7d0+8 = 0x7ffee335f7d8 。刚好是person的栈地址。所以最后打印的是person