iOS——内存分配与分区

这篇文章依次介绍一下iOS中内存的分配与分区。

1、RAM & ROM

  • 存储器(Memory)是计算机系统中的记忆设备,用来存放程序和数据。
  • iOS的存储器包括RAM(random access memory,运行内存)和ROM(Read-Only Memory,只读存储器)。
  • RAM:运行内存,不能掉电存储。
  • ROM:存储性内存,可以掉电存储,例如内存卡、Flash。
  • 由于 RAM 类型不具备掉电存储能力(即一掉电数据消失),所以 app 程序一般存放于 ROM 中。RAM 的访问速度要远高于 ROM,价格也要高。

2、App程序启动

  • App 程序启动,系统会把开启的那个 App 程序从 Flash 或 ROM 里面拷贝到内存(RAM),然后从内存里面执行代码。
  • 注意CPU 不能直接从内存卡里面读取指令!(需要 Flash 驱动)

3、iOS内存分区

  • iOS应用在内存(RAM)中运行,不同的类型在内存处于不同分区
  • 图中由进程箭头指向的代码段、全局数据段是在进程就绪状态时通过编译器装载进来的
  • 堆区、栈区、内存映射区域是在进程进入执行状态(即运行时)后向CPU(处理器)申请分配
  • 进程结束这些区域会随着销毁,保留区和内核区除外
  • 堆和栈是可增长的,它们的增长方向相对,堆向上增长,栈向下增长
    请添加图片描述

下面解释一下每个区域:

保留段

  • 系统分配出来的一块空闲区域,用来处理紧急情况下的任务

代码段

  • 储存编译完成之后的指令代码(可执行代码的二进制文件)
  • 在程序编译时存入,程序结束后由系统释放
  • 通常代码段是可共享的,这使得需要频繁被执行的程序只需要在内存中拥有一份拷贝即可
  • 代码段也通常是只读的,这样可以防止其他程序意外地修改其指令
  • 在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等

常量区

  • 存放常量字符串
  • 常量区的内存在编译阶段完成分配,程序运行时会一直存在内存中,只有当程序结束后才会由操作系统释放
  • iOS中常量区的地址空间一般以0x1开头

全局数据段(全局区/静态区)

  • static修饰的变量成为静态变量,该变量内存放在全局数据段
  • 由程序编译时创建,已初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量存放在另一块区域,直到程序结束才释放
  • iOS中全局数据段的地址空间一般以0x1开头

未初始化数据(Block Started by Symbol)

  • 简称BSS,存放程序中未初始化的全局变量、静态变量等数据
  • int a,并未赋值的变量a就被认为是未初始化数据

已初始化数据(data segment)

  • 简称DATA,存放程序中已初始化的全局变量、静态变量等数据
  • int a = 10NSString *strS = @"123456789"

堆区(heap)

  • 堆一般用来存储引用类型的对象数据
  • 堆从低地址向高地址扩展数据,采用链表形式管理内存段:需要分配时对链表进行遍历,找到空间大于申请的节点分配给开发者,然后在链表中删除节点。找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中
  • 变量使用结束后,需要由开发者根据引用计数来判断是否释放(ARC下由编译器自动添加释放命令),不释放可能引起内存泄露
  • 堆区的内存是应用程序共享的,堆中的内存分配是系统负责的
  • iOS中堆的地址空间一般以0x6开头,其空间总是在程序运行时动态分配
  • 堆由于是运行时开辟、且内存区域是不连续的,导致容易出现内存碎片

内存映射段

  • mmap文件映射和匿名映射:磁盘文件的数据映射到内存,通过修改内存就能修改磁盘文件
  • 该段可以理解为用来处理有关文件映射的内容

栈区(stack)

  • 存放程序临时创建的局部变量,也就是说我们函数括弧“{}” 中除了 static 定义之外的变量(static 变量存放在数据段),包括函数的参数以及隐藏参数(id self, SEL _cmd)
  • 栈从高地址向低地址扩展,是一块连续的内存区域,遵循先进后出原则,一旦出了作用域就会被销毁
  • 栈是系统数据结构,栈是在运行时开辟,其对应的线程或进程是唯一的
  • 程序员不需要管理栈区变量的内存,由编译器自动分配释放
  • iOS中栈的地址空间一般以0x7开头
  • 可用于函数调用的现场保护和现场恢复
  • 栈的内存大小有限制。根据苹果线程编程指南,iOS的主线程栈大小不超过1MB,OS X主线程栈最大8MB,子线程栈最大512KB。子线程在创建的时候可以更改栈的大小,子线程允许设置的最小栈大小为16 KB,并且栈大小必须为4 KB的倍数。主线程的栈大小无法修改。

内核区

  • 系统内核运行的区域
  • iOS的核心是XNU内核;XNU内核是一个混合内核,其核心是一个叫Mach的微内核

一般说的五大分区

  • 堆区、栈区、全局区、常量区、代码区
  • 一段代码看出变量在哪个区
int i = 10; //全局初始化
char *a; //全局未初始化
- (void)test {
    int b;//栈区
    NSString *str = @"123";//常量区
    static int c = 0;//全局(静态)初始化区
    NSObject *obj = [[NSObject alloc]init];//堆区
}

其它操作系统

  • iOS 是基于 UNIX、Android 是基于 Linux 的,在 Linux 和 unix 系统中,内存管理的方式基本相同,Android 应用程序的内存分配也是如此
  • 这些应用层的程序使用的都是虚拟内存,它们都是建立在操作系统之上的,只有开发底层驱动或板级支持包时才会接触到物理内存。在嵌入式 Linux 中,实际的物理地址只有 64M 甚至更小,但是虚拟内存却可以高达 4G

注意事项

  • 当一个 app 启动后,代码区、常量区、全局区大小已固定,因此指向这些区的指针不会产生崩溃性的错误。而堆区和栈区是时时刻刻变化的(堆的创建销毁,栈的弹入弹出),所以当使用一个指针指向这两个区里面的内存时,一定要注意内存是否已经被释放,否则会产生程序崩溃(野指针报错等)。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值