iOS内存分配-栈和堆

2,106 阅读5分钟

前言

移动设备的内存有限,每一个APP所能占用的内存是有限制的

什么行为会增加APP的内存占用?

  • 创建一个OC对象
  • 定义一个变量
  • 调用一个函数或方法

内存管理范围

  • 只有OC对象需要内存管理
  • 非OC对象类型比如基本数据类型就不需要进行内存管理

引入堆和栈

只有OC对象需要进行内存管理的本质原因?

因为OC对象在内存中是以堆的方式分配内存的
堆内存是由我们自己释放的(release)

而非OC对象一般存在栈里
栈内存会被系统自动回收

进程内存区域

image.png

  1. 代码区:代码段是用来存放可执行文件的操作指令(存放函数的二进制代码),也就是说是它是可执行程序在内存种的镜像。代码段需要防止在运行时被非法修改,所以只准读取操作,而不允许写入(修改)操作——它是不可写的。

  2. 常量区:常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,

  3. 全局(静态)区

    放全局变量和静态变量,包含下面两个分区:

  • 数据区:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量
  • BSS区:BSS段包含了程序中未初始化全局变量
  1. 堆(heap)区:堆是由程序员分配和释放,用于存放进程运行中被动态分配的内存段,它大小并不固定,可动态扩张或缩减
  • 当进程调用alloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)
  • 当利用realse释放内存时,被释放的内存从堆中被剔除(堆被缩减),因为我们现在iOS基本都使用ARC来管理对象,所以不用我们程序员来管理,但是我们要知道这个对象存储的位置
  1. 栈(stack)区:栈是由编译器自动分配并释放,用户存放程序临时创建的局部变量,存放函数的参数值,局部变量等
  • 也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味这在数据段中存放变量)
  • 除此以外在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中
  • 由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上将我们可以把栈看成一个临时数据寄存、交换的内存区

代码举例

int age = 24;//全局初始化区(数据区)
NSString *name;//全局未初始化区(BSS区)
static NSString *sName = @"Dely";//全局(静态初始化)区

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    int tmpAge;//栈
    NSString * tmpName = @"Dely";//栈
    NSString * number = @"123456"; //123456\0在常量区,number在栈上。
    NSMutableArray * array = [NSMutableArray arrayWithCapacity:1];//分配而来的8字节的区域就在堆中,array在栈中,指向堆区的地址
    NSInteger total = [self getTotalNumber:1 number2:1];

}

- (NSInteger)getTotalNumber:(NSInteger)number1 number2:(NSInteger)number2{
    return number1 + number2;//number1和number2 栈区
}
@end

堆和栈的区别

  1. 申请后的系统响应
  • 栈:存储每一个函数在执行的时候都会向操作系统索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和释放,内存随着函数的运行分配,随着函数的结束而释放,由系统自动完成。

注意:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

  • 堆:
    • 首先应该知道操作系统有一个记录空闲内存地址的链表。
    • 当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
    • 由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中
  1. 申请大小的限制
  • 栈:栈是向低地址扩展的数据结构,是一块连续的内存的区域。是栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数 ) ,如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

  • 堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

  1. 申请和回收的方式
  • 栈区:由编译器自动分配并释放
  • 堆区:由程序员分配和释放
  1. 申请效率的比较
  • 栈区:由系统自动分配,速度较快(但是程序员不能控制)
  • 堆区:由alloc分配的内存速度较慢
  1. 分配方式的比较
  • 栈区:静态分配和动态分配
    • 静态分配:系统自动分配,例如局部变量
    • 动态分配:alloc函数分配
  • 堆区:都是动态分配,没有静态分配的堆
  1. 分配效率的比较
  • 栈区:系统分配专门的寄存器存放栈的地址,出栈压栈都有专门的指令执行,分配效率较高
  • 堆区:为了分配一块内存,库函数需要根据一定的算法在堆内存中找到可用的空间,分配效率较低

参考博客:www.cnblogs.com/fengmin/p/6…