【iOS】iOS内存五大分区

news2025/1/16 5:34:21

iOS内存五大分区

总揽

iOS中,内存主要分为五大区域:栈区,堆区,全局区/静态区,常量区和代码区。总览图如下。
在这里插入图片描述

这个图我觉得更好记,因为下面是低地址,上面是高地址,是比较符合日常逻辑的。
由下到上开始背:代码区,常量区,全局/静态区,堆区(向上生长),栈区(向下生长),内核区

如上图所示,代码区是在低地址段存放,而栈区则存放在高地址段,并且各个分区之间不是连续的。

栈区

1.1 介绍

  • 栈是从高地址向低地址存储的一块连续的内存区域,特点是先进后出(FILO)
  • 栈的地址空间在iOS里面 0X7 / 0X16 开头
  • 栈区一般是在 运行时分配内存,内存空间由系统管理, 也就是变量超出了自身的作用范围之后就会被释放
  • 包含 函数内部定义的局部变量以及方法参数(方法的默认参数self、cmd)等也都是存放在栈区

1.2优缺点

  • 注意,栈区的内存是由系统分配并管理的,所以它会由系统分配并自己释放,不会产生内存碎片,更快更高效。
  • 但是栈的内存大小被系统所限制导致其并不是很灵活,iOS主线程栈道大小1MB,其他线程512KB,Mac为8M
    在这里插入图片描述
- (void)testStack {
    int a = 10;

    NSLog(@"a == %p size == %lu",&a,sizeof(a));
    NSLog(@"方法参数 self:%p",&self);
    NSLog(@"方法参数 cmd:%p",&_cmd);
}

在这里插入图片描述

可以看出,栈内存的分配是连续的参数如栈顺序为,self, _cmd, a。然后地址的大小变化为0x16b8cba28 -> 0x16b8cba20 -> 0x16b8cba1c (可以看出由高地址到低地址,一次递减8字节

堆区

  • 堆是从低地址向高地址的不连续的内存区域,和链表的结构很相似(便于增删但不便于查询),特点是先进先出(FIFO)
  • 堆地址是以0x6开头,动态的分配空间
  • 在堆里面存放的东西需要我们手动的管理和释放,若不及时释放就会造成内存泄漏
  • 在OC里面alloc和new都会为对象开辟空间到堆上
- (void)testHeap {
    NSObject *object1 = [NSObject new];
    NSObject *object2 = [NSObject new];
    NSLog(@"object1 = %@",object1);
    NSLog(@"object2 = %@",object2);
}

在这里插入图片描述

可以看出,堆内存分配是 不连续的

栈和堆的区别联系

  1. 各自的优缺点?
  • 栈:由编译器自动分配并释放,速度较快,不会产生内存碎片。优点是快速高效,缺点是有限制,数据不灵活。
  • 堆: 由程序员分配和释放,速度比较慢,而且容易产生内存碎片,不过用起来最方便。优点是灵活方便,数据适应面广泛,但是效率有一定降低
  1. 申请后的系统如何响应?
  • 栈:存储每一个函数在执行的时候都会向操作系统索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和释放,内存随着函数的运行分配,随着函数的结束而释放,由系统自动完成。只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
  • 堆:操作系统有一个记录空闲内存地址的链表。当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空间结点链表中删除,并将该结点的空间分配给程序。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
  1. 申请大小的限制?
  • 栈: 栈是向低地址扩展的数据结构,是一块连续的内存的区域。栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈道剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
  • 堆: 堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

全局/静态区

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

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

int clB;
static int bssB;
int initClB = 10;
static int initBssB = 11;
- (void)testStatic {
    NSLog(@"clA = %p", &clB);
    NSLog(@"bssB = %p", &bssB);
    NSLog(@"initClB = %p", &initClB);
    NSLog(@"initBssB = %p", &initBssB);
}

在这里插入图片描述

结论:
clB 和 bssB都是未初始化,在内存是连续的地址,相差为4。
initClB和 initBssB都是初始化的数据,内存地址也是连续的,也相差4。

常量区

  • 该区是编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放。
  • 存放常量: 整形、字符型、浮点、字符串等
  • 常量区是编译时分配的内存空间,在程序结束后由系统释放,主要存放:
    • 已经使用了的,且没有指向的字符串常量
    • 字符串常量因为可能在程序中被多次使用,所以在程序运行之前,就回提前分配内存。

代码区

  • 该区时编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放
  • 程序运行时的代码会被编译成二进制,存进内存的代码区域

面试题

  1. 讲一下static关键字的各种情况以及作用

答:

  • 对于全局变量来说,static 改变了其作用域。普通全局变量是所有文件都可以用。静态全局变量是只有当前文件可以用。
  • 对于局部变量来说,static改变了其存储方式从而改变了生命周期。普通局部变量是动态存储,动态存储决定了其生命周期为变量使用期间。静态局部变量是静态存储,存储在全局静态区,生命周期为从程序开始道结束。
  • 因此 static 这个说明符在不同的地方所起的作用是不同的。
  • 总结:全局变量、静态全局变量、静态局部变量采用静态存储方式,局部变量采用动态存储方式。

更详细文章看这里:
iOS的static修饰符

  1. 问题1:请简述iOS应用程序的五大内存分区及其主要用途。

答案:
iOS应用程序的内存分为以下五个主要分区:

1. **栈(Stack)**:
   - **用途**:用于存储局部变量、函数参数、返回地址等。栈内存是自动分配和释放的,主要用于函数调用和局部变量的管理。
   - **特点**:内存分配方式为LIFO(后进先出),存取速度快,空间相对较小。

2. **堆(Heap)**:
   - **用途**:用于动态分配内存,存储需要在运行时分配和释放的对象和数据。堆内存由程序员手动管理,通过`malloc`、`free`、  `new`、`delete`等函数进行分配和释放。
   - **特点**:内存管理灵活,存储空间较大,但分配和释放速度相对较慢,容易产生内存碎片。

3. **全局区/静态区(Global/Static)**:
   - **用途**:存储全局变量和静态变量。全局变量在程序启动时分配,在程序结束时释放;静态变量在第一次使用时分配,程序结束时释放。
   - **特点**:内存地址固定,生命周期贯穿程序运行的整个周期。

4. **常量区(Constant)**:
   - **用途**:存储常量数据,例如字符串常量、数值常量等。常量区的内容在程序运行时不可修改。
   - **特点**:只读区域,数据在程序加载时初始化,生命周期贯穿程序运行的整个周期。

5. **代码区(Code/Text)**:
   - **用途**:存储程序的可执行代码,包括函数体和编译后的指令。代码区在程序运行时是只读的,以防止意外修改。
   - **特点**:只读区域,存储的是编译后的机器指令,生命周期贯穿程序运行的整个周期。
  1. 问题2:为什么栈内存的分配和释放速度比堆内存快?

答案:
1. 分配方式:栈内存采用LIFO(后进先出)的分配方式,每次函数调用时,函数的局部变量、参数和返回地址会依次入栈,函数返回时,这些数据会依次出栈。分配和释放只需要移动栈指针,操作简单且高效。

2. **内存管理**:栈内存由系统自动管理,函数调用结束时,系统会自动释放栈内存,无需程序员手动管理。堆内存则需要程序员手动管理,通过`malloc`、`free`等函数进行分配和释放,管理复杂且容易产生内存碎片。

3. **空间连续**:栈内存通常是连续的内存块,分配和释放时不需要进行复杂的内存碎片整理,而堆内存由于频繁的分配和释放,容易产生内存碎片,导致分配和释放速度变慢。
  1. 问题3:什么是内存碎片?如何在iOS开发中避免内存碎片?

答案:
内存碎片是指由于频繁的内存分配和释放,导致堆内存中出现大量无法使用的小块空闲内存,从而降低内存利用效率和分配速度。

在iOS开发中,避免内存碎片的方法包括

1. **使用自动内存管理**:iOS使用ARC(Automatic Reference Counting)来自动管理内存,减少手动分配和释放内存的操作,从而降低产生内存碎片的风险。

2. **对象池技术**:对于频繁使用的对象,可以使用对象池(Object Pool)技术,将对象复用,而不是每次都创建新的对象,从而减少内存分配和释放的次数。

3. **尽量避免频繁的内存分配和释放**:对于需要频繁分配和释放内存的操作,可以考虑优化算法或数据结构,减少内存分配和释放的频率。

4. **使用合适的数据结构**:在设计数据结构时,尽量使用内存连续的数据结构,例如数组、链表等,避免过度使用需要频繁分配和释放内存的复杂数据结构。
  1. 问题4:全局区和静态区的内存是如何管理的?它们之间有什么区别?

答案:
全局区和静态区的内存管理方式如下:

- **全局区(Global)**:
  - 管理全局变量,即在程序的整个生命周期内都存在的变量。==这些变量在程序启动时分配内存==,在程序结束时释放内存。
  - 全局变量在定义时如果未显式初始化,系统会将其初始化为0。

- **静态区(Static)**:
  - 管理静态变量,即在函数或类内部定义并带有`static`关键字的变量。==这些变量在第一次使用时分配内存==,在程序结束时释放内存。
  - 静态变量在第一次定义时如果未显式初始化,系统也会将其初始化为0。

**区别**:
- **生命周期**:全局变量和静态变量的生命周期相似,都是在程序运行期间存在,但全局变量在程序启动时即被初始化,而静态变量在第一次使用时才被初始化。
- **作用域**:全局变量的作用域是整个程序,而静态变量的作用域仅限于其定义的函数或类内部。
  1. 问题5:代码区是只读的,这对程序安全性有什么影响?

答案:
代码区是只读的,这对程序的安全性有以下影响:

1. **防止代码篡改**:代码区的只读属性确保了程序在运行时,代码段不能被修改,从而防止恶意代码注入和篡改。这提高了程序的安全性,防止了病毒和恶意软件的攻击。

2. **保护执行环境**:由于代码段是只读的,任何对代码区的写操作都会引发异常,从而防止意外或恶意修改代码指令,保证了程序的稳定运行。

3. **避免缓冲区溢出攻击**:许多攻击技术,例如缓冲区溢出攻击,试图通过修改程序的执行路径来执行恶意代码。代码区的只读属性可以有效防止这些攻击,因为即使攻击者试图修改代码,系统也会检测到并阻止操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea 2024 中文最新版破解激活永久(图文详细讲解教程)超级简单(亲测可用)

1.官网下载:下载地址 2.点击下载完成之后,找到下载路径,双击运行exe文件,进行安装 3.安装完成后,在桌面找到idea快捷方式,双击运行 4.此时是没有激活的,点击关闭窗口,然后退出程序 5…

nginx代理设置时能获取到源IP地址的方法

nginx通过http_x_forwarded_for限制来访IP示例_ngnix 根据header的x-forwarded-for限制接入-CSDN博客 名称ip客户端地址10.0.23.90nginx服务器地址110.0.202.48:18888,代理到10.0.204.82:8888nginx服务器地址210.0.204.82:8888,代理到10.0.204.82:8887后…

充电宝买多少毫安的好?选充电宝这几个关键点必看!

在如今这个电子设备不离手的时代,充电宝成为了我们生活中的必备品。然而,面对市场上琳琅满目的充电宝,选择合适容量的充电宝却让许多人感到困惑。充电宝买多少毫安的好?这可不是一个简单的问题。容量太小,无法满足我们…

20240802 每日AI必读资讯

🌐太离谱!曝GPT-4o mini没做安全测试就开庆功会! - OpenAI曾向美国政府承诺,将严格对其前沿的突破性技术进行安全测试,以确保AI不会造成损害,比如教用户制造生化武器或帮助黑客开发新型网络攻击。 - Open…

canvas根据图片生成粒子动画

canvas根据图片生成粒子动画 效果展示: canvas根据图片生成粒子动画效果 注意: js和css的引入 id: cartoonDot-img对应的是被 拷贝的图像,后期要替换的 粒子图像就在这 min.js 地址 HTML代码块 <!DOCTYPE html> <html><head><meta charset=&quo…

面向对象编程在Python中的应用

引言 面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;是一种程序设计范式&#xff0c;它使用“对象”来设计软件。在Python中&#xff0c;OOP提供了一种结构化的方式来组织代码&#xff0c;使得程序更加易于理解和维护。本文将介绍一些基本的面向对象编…

洗地机哪个品牌好用?智能洗地机品牌排行榜揭晓

在追求家居清洁智能化的今天&#xff0c;洗地机品牌众多&#xff0c;选择一款好用且智能的洗地机成了许多家庭的关注点。本文精心揭晓智能洗地机品牌排行榜&#xff0c;为大家精选出市场上性能卓越、用户口碑极佳的品牌&#xff0c;如滴水、以内、希亦等&#xff0c;它们凭借创…

电池数据巡检时发现的数据问题处置措施

电池监控系统在日常使用中需要关注电压不均告警和内阻不均告警&#xff0c;对偏差大的单体电池核实处理。 一、电池单体电压偏差 出现电池单体电压偏差有两种情况&#xff0c;一种是电池故障&#xff0c;另一种是电池单体采集模块故障。现场需要用万用表对异常单体电压进行测量…

轻松入门Linux—CentOS,直接拿捏 —/— <5>

一、Linux常用工具 1、tar打包命令详解 当 tar 命令用于打包操作时&#xff0c;该命令的基本格式为&#xff1a; tar [选项] 源文件或目录 常用选项&#xff1a; 1.1 打包文件 例如&#xff0c;我有几个文件&#xff0c;将他们打包成一个文件&#xff0c;以tar结尾的后缀名 …

新手小白,如何新建一个springboot的web项目?

第一步&#xff1a;打开软件&#xff0c;点击file&#xff0c;点击new 然后选择module&#xff0c;在右侧选择springboot 第二步&#xff1a;选择配置和JDK以及java版本 ①选择maven类型 ②选择JDK1.8版本 ③选择java8版本 ④选择jar包类型 如果不知道或者找不到配置8版本&…

【JVM】类加载器和双亲委派模型

什么是类加载器 如果想要了解什么是类加载器就需要清楚一个Java文件是如何运行的。我们可以看下图&#xff1a; 首先要知道操作系统是不能直接运行Java文件的&#xff0c;所以就需要通过JVM将Java文件转换为操作系统可以运行的文件类型&#xff0c;步骤如下&#xff1a; 类加…

lua学习(1)

1. lua 字符串 单个引号和双引号都可变量的定义默认是全局的删除一个变量将其赋值为nil即可 如&#xff1a; bnilnil还可以对表中的数据进行删除&#xff0c;也可删除一个表只要变量不是nil&#xff0c;变量即存在标识符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后&am…

网安加·百家讲坛 | 高明:模糊测试技术在车联网安全性评估中的应用

作者简介&#xff1a;高明&#xff0c;信息安全硕士&#xff0c;10年以上软件安全开发和产品架构设计经验。成功主导多个模糊测试和车联网安全相关的产品研发与项目实施&#xff0c;并参与网络安全产品相关行业标准的编写。擅长产品规划和敏捷项目管理&#xff0c;持有PMP、PgM…

SFP-8636 QSFP光模块解析学习

对于QSFP 100G模块,我们参考SFF-8636协议文档,暂时访问的寄存器一般位于page0, 此时0x7f写0即可, 1,状态静态数据 -->iic read 1 0 a0 80 Read i2c_bus[1] dev_addr[0xa0] reg[0x80] success, r_data[0xd] -->iic read 1 0 a0 82 Read i2c_bus[1] dev_addr[0x…

如何实现AI无人带货直播间?

在数字化时代&#xff0c;直播电商已成为推动商品销售的重要力量&#xff0c;随着人工智能(AI)技术的不断发展&#xff0c;AI无人带货直播间作为一种创新的商业模式正逐渐崭露头角。 这种直播间通过集成先进的AI技术&#xff0c;如自然语言处理、图像识别、机器学习等&#xf…

园区导航小程序:一站式解决园区导航问题,释放存储,优化访客体验

随着园区的规模不断扩大&#xff0c;功能区划分日益复杂&#xff0c;导致访客和新员工在没有有效导航的情况下容易迷路。传统APP导航虽能解决部分问题&#xff0c;但其下载安装繁琐、占用手机内存大、且非高频使用导致的闲置&#xff0c;让许多用户望而却步。园区导航小程序的出…

武汉流星汇聚:跨境电商助力中国卖家打造全球品牌,赢得国际声誉

在全球零售电商行业稳健增长的大潮中&#xff0c;跨境电商平台如同一座桥梁&#xff0c;连接着中国卖家与全球消费者&#xff0c;不仅促进了商品的快速流通与市场的广泛覆盖&#xff0c;更为中国卖家提供了提升品牌知名度和美誉度的宝贵机遇。 随着全球化进程的加速&#xff0…

arduino程序-逻辑控制(基础知识)

arduino程序-逻辑控制&#xff08;基础知识&#xff09; 1-15 逻辑控制1-按键开关控制LED效果演示输入上拉模式电路示例程序 1-16 逻辑控制2-布尔变量逻辑表达式改写程序&#xff08;使用布尔运算&#xff09;程序上传及效果演示回顾知识 1-17 逻辑控制3-布尔运算效果演示布尔运…

Spring Boot使用Disruptor做内部高性能消息队列

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 背景 在现代应用开发中&#xff0c;特别是在构建高并发、低延迟的系统时&#xff0c;内部高性能消息队列的作用变得尤为重要。内部高性能消息队列&#xff0c;如Disruptor&#xff0c;为应用提供了一种高效、…