OC基础知识点之-内存管理初识(内存分区)

1,984 阅读4分钟

系列文章:OC底层原理系列OC基础知识系列

之前文章我们说了KVO键值观察,此处传送门,这篇文章 来讲一下iOS的内存。我们知道iOS内存主要有一下五大区域,分别是栈区、堆区、全局区、常量区、代码区其中全局区和常量区有叫数据段(_DATA区)。下面我们分别来看下每个区的作用

栈区(Stack)

定义

  • 1.栈是系统数据结构,其对应的进程或者线程是唯一
  • 2.栈是从高向低地址扩展的数据结构
  • 3.栈是一块连续的内存区域,遵循先进后出的原则:FILO(入栈,出栈)
  • 4.栈的地址空间在iOS中通常以0x7开头
  • 5.栈区一般在运行时进行分配 栈区空间大小较小,所以空间比较宝贵,但是读取写入效率高,下面我们看看栈区都会存储什么内容

存储

栈区一般是由编译器来自动分配和释放的,主要用来存储一下内容

  • 局部变量
  • 函数的参数,例如函数的隐藏参数(id self,SEL_cmd)

优缺点

  • 优点
    • 不会产生内存碎片(回收释放有系统自己控制)
    • 高效的读写速度
  • 缺点
    • 栈的内存较小(iOS主线程栈大小1MB,其它线程512KB)
    • 存储数据不灵活(存储内容基本固定,由编译器分配)

堆区(Heap)

定义

  • 1.堆是从低向高地址扩展的数据结构
  • 2.堆是不连续的内存区域,类似于链表结构,遵循先进先出原则:FIFO
  • 3.堆的地址空间在iOS中通常以0x6开头
  • 4.堆区的分配一般也是在运行时进行分配

存储

堆区一般是由开发者自己分配和释放的,同时系统也会在必要的时候对堆区存储的内容进行回收和释放(系统检测属性或者对象引用计数为零时,进行回收

  • OC使用alloc、new、block或者使用copy创建的对象都会存在这里(ARC下编译器会自动在合适的时候释放内存,而在MRC下需要开发者手动释放)
  • C语言中使用malloc、calloc、realloc分配的空间(需要free释放)

优缺点

  • 优点
    • 使用灵活方便,数据使用更加广泛
  • 缺点
    • 内存需要手动管理
    • 容易产生碎片
    • 读取速度和栈区比较慢 访问堆区内存时,一般是先通过对象读取到对象所在的栈区的指针地址,然后通过指针地址访问堆区

全局区(静态区,即bss段)

全局区是又叫BSS段,是编译期分配的内存空间,在iOS一般是以0x1开头,在程序运行的过程中该数据就一直存在,程序结束后再由系统释放

存储

  • 未初始的全局变量
  • 未初始化静态变量 全局变量或者静态变量一旦被初始化后,就会被回收,并将数据转存到常量区

常量区

常量区是专门存放常量的,只有程序结束才会被回收

存储

  • 初始化过得全局变量
  • 初始化过得静态变量

代码区

编译期分配,主要用于存放程序运行的代码代码会被编译成二进制存进内存中该程序中的代码区程序结束时系统会自动回收存储在代码段中的数据

代码验证

我们进行代码验证一下五大区域,准备代码: 运行代码:

总结

通过上面的运行结果,我们进行以下总结:

  • 1.栈区地址一般是0x7开头
  • 2.堆区地址一般是0x6开头
  • 3.而全局区一般是0x1开头
  • 4.未初始化的静态变量地址比已初始化过的静态变量地址大(全局区的地址比常量区地址高)
  • 5.栈区空间是连续的,其内存地址是从高向低方向分配的。
  • 6.堆区空间是从低到高地址分配的(我们看到alloc对象和字符串分别是从低到高,但是alloc对象和字符串比较不符合)
  • 7.字符串的直接赋值是放在常量区的,而通stringWithFormat是放在堆区的。
  • 8.alloc对象在堆区,但是其对象指针地址在栈区。 根据上面的总结我们画张图

写到最后

这里我们主要介绍了iOS内存的五个区域,后续有时间,我会补充内存管理的其它内容,比如自动释放池,引用计数,SideTable等内存管理的相关内容