[iOS] 内存五大区

1. 介绍

iOS中,内存主要分为栈区堆区全局区常量区代码区五大区域,如下图所示:

image.png

2. 栈区

2.1 介绍
  • 栈是系统的数据结构,其对应的进程或者线程是唯一的
  • 栈是从高地址向低地址扩展的数据结构
  • 栈是一块连续的内存区域,遵循FILO,先进后出原则
  • 在iOS中一般以0x7开头,在运行时分配
  • 编译器自动分配释放,不会产生内存碎片,快速高效
  • 内存大小有限制,数据不灵活(主线程栈是1MB,其他线程是512KB
2.2 存储的数据

栈区的内存是由编译器自动分配并释放的,主要用来存储:

  • 函数内部定义的局部变量和数组
  • 函数的参数
    栈区的内存空间是由系统管理,在调用的时候开辟空间,函数调用完成,就收回空间。

3. 堆区

3.1 介绍
  • 和栈相反,堆是低地址向高地址扩展的数据结构
  • 堆是不连续的内存区域,类似于链表,遵循先进先出原则
  • 堆的地址空间在iOS中以0x6开头,一般在运行时动态分配空间
  • 需要手动管理,容易产生内存碎片
3.2 存储的数据

堆区主要由开发者动态分配和释放,如果开发者不释放,程序结束后,则由操作系统回收

  • OC中使用alloc或者使用new开辟空间创建对象
  • C语言中使用malloccallocrealloc分配的空间,需要free释放

注意:当需要访问堆中内存时,一般需要先通过对象读取到栈区的指针地址,然后通过指针地址访问堆区

4. 全局区 (静态区,.bss & .data)

  • 全局区是在编译时分配的内存空间
  • 全局区的地址空间在iOS中一般以0x1开头
  • 程序运行中,内存中的数据一致存在,程序结束后由系统释放
  • .bss(BSS)区存放未初始化的全局变量和静态变量
  • .data 数据区存放已经初始化的全局变量和静态变量

其中,全局变量是指变量值可以在运行时被动态修改,而静态变量是static修饰的变量,包含静态局部变量和静态全局变量。

5. 常量区 (.rodata)

常量区是编译时分配的内存空间,在程序结束后由系统释放,主要存放已经使用了的,且没有指向的字符串常量。
字符串常量可能会在程序中多次使用,所以在程序运行之间就会提前分配内存。

6. 代码区(.text)

代码区是编译时分配主要用于存放程序运行时的代码,代码会被编译成二进制存进内存的。

7. 验证

举个例子,看看下面的代码,变量在内存中是如何分配的:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSInteger i = 123;
    NSLog(@"i的内存地址:%p", &i);
    
    NSString *string = @"CJL";
    NSLog(@"string的内存地址:%p", string);
    NSLog(@"&string的内存地址:%p", &string);
    
    NSObject *obj = [[NSObject alloc] init];
    NSLog(@"obj的内存地址:%p", obj);
    NSLog(@"&obj的内存地址:%p", &obj);
}

输出结果如下:

2021-01-19 20:38:48.645299+0800 KVC[42501:2211601] i的内存地址:0x7ffee4107138
2021-01-19 20:38:48.645439+0800 KVC[42501:2211601] string的内存地址:0x10baf9040
2021-01-19 20:38:48.645553+0800 KVC[42501:2211601] &string的内存地址:0x7ffee4107130
2021-01-19 20:38:48.645663+0800 KVC[42501:2211601] obj的内存地址:0x600001ba8110
2021-01-19 20:38:48.645761+0800 KVC[42501:2211601] &obj的内存地址:0x7ffee4107128
  • 对于局部变量i,地址是0x7开头的,存放在栈区
  • 对于字符串对象stringstring的对象地址是0x10baf9040,存放在常量区,存放string对象指针的地址是0x7ffee4107130,存放在栈区
  • 对于alloc创建的对象obj,对象的内存地址是0x600001ba8110,存放在堆区,存放obj对象指针的地址是0x7ffee4107128,存放在栈区

8. 函数栈&栈帧

  • 函数栈又称为栈区,在内存中从高地址往低地址分配,与堆区相对
  • 栈帧是函数(运行中)占用的一块独立的连续内存区域
  • 应用中新创建的每个线程都有专用的栈空间,栈可以在线程期间自由使用。而线程中有千千万万的函数调用,这个函数共享一个栈空间。栈帧就是这个函数在栈空间里独占的部分,所有的栈帧就组成了这个线程完整的栈。
  • 函数调用是发生在栈上的,每个函数的相关信息(例如局部变量调用记录等)都存储在一个栈帧中,每执行一个函数调用,就会生成一个与其相关的栈帧,然后将其栈帧压入函数栈,当函数执行完毕,对应的栈帧也会出栈并释放掉。

如下图所示,是经典图 - ARM的栈帧布局方式:

image.png

  • 其中main stack framemain函数的栈帧,func1 stack frame 为当前函数(被调用者)的栈帧
  • 栈底是高地址,向下增长
  • FP是栈基址,指向栈帧起始地址,SP是栈顶指针,指向栈顶位置
  • ARM压栈是有顺序的,依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。如果函数准备调用另一个函数,跳转之前临时变量区先要保存另一个函数的参数
  • ARM也可以用栈基址和栈指针明确标示栈帧的位置,栈顶指针SP一直移动,ARM的特点是,两个栈空间内的地址(SP+FP)前面,必然有两个代码地址(PC+LR)明确标示着调用函数位置内的某个地址。

注意:一般情况下是不需要考虑堆栈的带下,但是事实上它们都是有限制的,过多的递归会导致栈溢出,过多的alloc对象会导致堆溢出。

推荐 阮一峰-汇编语言入门教程

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容

  • 在iOS中,内存主要分为 栈区、堆区、全局区、常量区、代码区 五大区域。如下图所示 下面分别介绍这五大区 栈区(S...
    恍然如梦_b700阅读 675评论 0 2
  • 在 iOS 开发中,内存主要分为堆区、栈区、全局区、常量区、代码区五大区域 堆(heap)区 是有程序员分配和释放...
    远方竹叶阅读 2,261评论 1 11
  • iOS内存主要分成栈区、堆区、全局区、常量区、代码区这五大区域。如下图所示: 栈(Stack) 栈是由高地址向低地...
    iOSer_jia阅读 870评论 0 2
  • iOS内存五大区 在iOS中,内存主要分为:栈区、堆区、全局区(静态区)、常量区以及代码区这五大区。本文将对这五大...
    just东东阅读 1,853评论 0 5
  • 从高地址向低地址排序: 栈区<运行时分配>: 特点:由编译器自动完成分配和释放,不需要程序员手动管理,主要存储了函...
    wp_Demo阅读 1,004评论 0 3