之前文章我们说了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等内存管理的相关内容