内存管理-内存布局

880 阅读2分钟

在我们开发过程中基本时时刻刻都会跟内存打交道,那么在底层内存又是如何分布的呢?相信这也是大家比较想知道的,下面我们就来介绍下。

image.png

如图所示我们可以看到,内存除了内核区与保留区,我们平时用到的分为五大区域,地址由高到低分别是栈区, 堆区, 未初始化数据区, 已初始化数据区, 代码段区,下面我们分别来介绍这五大区域。

栈区(stack)

栈区一般存放函数, 方法, 指针, 局部变量, 参数等。栈区的内存一般通过 sp 寄存器去定位。而堆区需要先通过寄存器定位到指针,再通过指针定位到指定的堆区域,所以栈区的速度相对于堆区的速度是非常非常的快的。

堆区(heap)

一般需要开辟空间来存储的都会放到堆区,例如我们通过 clloc, new 等创建出来的对象,一般需要的空间比较大。例如我们的结构体,需要一大段空间来容纳成员变量。

未初始化数据区, 已初始化数据区, 代码段区

App 开始加载的时候数据都是存放在未初始化数据区, 已初始化数据区, 代码段区这三个地方,只有程序真正运行的时候才会开辟堆区空间。程序的加载主要就是控制这三块区域。

// 未初始化数据
static int bssA;
static NSString *bssStr1;

// 已初始化数据
static int bssB = 10;
static NSString *bssStr2 = @"cooci";

.bss.data 统称为全局区,但是他们分为已初始化数据与未初始化数据,如代码中 bssAbssStr1 为未初始化数据,没有被赋值, bssBbssStr2 为已初始化数据。我们应该也都听过讲 “static 修饰过的成员变量不在内存”,其实这个说法是不严谨的,只是 static 修饰过的成员变量只是在全局区,不占用对象申请开辟的空间。代码段为程序代码,加载到内存中。

image.png

如图是我们用 MachOView 工具读取的一个 MachO 文件,可以看到section 部分的数据段跟代码段的结构。

补充

内核区

假设总共有 4GB 的内存,系统保留了 1GB 供内核使用,剩下的 3GB 供外部使用,内核主要做一些消息间的转发处理及一些系统级别的控制。

保留区

系统保留一些低地址空间来做一些 nil 等下层字段的处理。

各内存区域开头地址

  • 栈区内存地址一般为:0x7 开头
  • 堆区内存地址一般为:0x6 开头
  • 数据段, BSS 内存地址一般为:0x1 开头