当前位置: 首页 > ds >正文

【iOS】内存分区

内存分区

  • 五大分区是什么?
    • 栈区
    • 堆区
    • 静态区 全局区
    • 常量区
    • 代码区
  • static、extern、const比较
    • static
    • extern全局变量
    • const常量

五大分区是什么?

在编写代码变量都是怎么在内存中存取的呢?其实内存中分为五大分区,分别是栈区(系统管理的地方)、堆区(程序员控制的地方)、常量区(全局区)、静态区、代码区。这里我们还要知道内存指的就是RAM

在这里插入图片描述

栈区

创建临时变量时由编译器自动分配,在不需要的时候自动消除变量的存储区。
主要用于存储函数的局部变量、函数参数和返回地址,遵循一个先进先出的原则我们可以把栈看做一个临时寄存,交换的内存区

用户栈在程序执行期间可以动态地扩展和收缩

优点:

  • 栈是系统数据结构,对应的线程/进程是唯一的,栈中存储了进程所需要的所有局部变量、函数的参数等内容
  • 栈的优点是快速高效,但是缺点是有限制,数据不灵活
  • 栈空间分为静态分配和动态分配两种,静态分配由编译器完成,动态分配在运行时决定的。
  • 为可移植的程序起见,栈的动态分配操作是不被鼓励的。

堆区

就是由allocnewmallocrealloc创建的对象所分配的内存块,他们的释放系统不会主动去管,需要我们开发者去告诉系统什么时候释放这块内存;若是程序猿不释放,程序结束后系统会自己释放。

堆是向高地址扩展的数据结构,是不连续的内存区域,程序员负责在何时释放内存(在ARC中通常会自动回收)。

优点:

  • 灵活方便、数据适应面广泛,但是效率有一定降低
  • 堆是函数库内部数据结构,不一定唯一
  • 不同堆分配的内存无法相互操作
  • 堆空间的分配总是动态的
  • 虽然程序结束时所有的数据结构都会被释放回系统,但是精准的申请内存,释放内存匹配时良好的程序基本要素

这里我们以下面这个分配堆内存为例:

NSObject* obj = [NSObject new]
  1. 在堆内存中申请一块大小合适的空间
  2. 在这块内存空间里创建我们的对象
  3. 初始化对象的属性,为对象的属性赋上默认值,基本数据类型赋值0 —— C语言类型为NULL —— OC指针类型为nil
  4. 返回这个对象在堆空间的地址,将这个地址赋给obj,这样以后我们访问obj变量时实际访问的就是堆空间中的NSObject对象,但是obj变量因为本质上是一个指针变量,他是存储在栈空间的

在这里插入图片描述

静态区 全局区

全局区分为两个区域,用于存储全局变量以及静态变量

  • .bss:存放未初始化的全局变量、静态变量
  • .data:已初始化的全局变量、静态变量

常量区

存放常量字符串,程序结束后由系统释放,该区是编译时分配的内存空间,在程序运行过程中,这个内存中的数据一直存在,程序结束后由系统释放。

代码区

用来存放函数的二进制代码,代码段需要防止在运行时被非法修改,故而只允许读取操作,不允许写入操作

static、extern、const比较

static

  • 全局静态变量

优点:无论对象方法还是类方法都可以访问和修改全局静态变量,并且外部类无法调用静态变量,定义后只会指向固定的指针地址,供所有对象使用,节省空间。

缺点:存在的生命周期长,从定义直到程序结束

建议:从内存优化和程序编译的角度来说,尽量少用全局静态变量,因为存在的生命周期长,一直占用空间。程序运行时会单独加载一次全局静态变量,过多的全局静态变量会造成程序启动慢。

static int counter = 0;
//可以在一个类中多个方法中使用
void increment() { counter++; }
void print_counter() { printf("Counter: %d\n", counter); }
  • 局部静态变量

优点:定义后只会存在一份值,每次调用都是使用的同一个对象内存地址的值,并没有重新创建,节省空间,只能在该局部代码块中使用。

缺点:存在的生命周期长,从定义直到程序结束,只能在该局部代码块中使用。

建议:局部和全局静态变量从本根意义上没有什么区别,只是作用域不同而已。如果值仅一个类中的对象和类方法使用并且值可变,可以定义全局静态变量,如果是多个类使用并可变,建议值定义在model作为成员变量使用。如果是不可变值,建议使用宏定义。

void log_message(const char* msg) {static int log_count = 0;printf("[%d] %s\n", ++log_count, msg);
}//仅在该函数中可以使用,不可以被外界访问

extern全局变量

//.m中要定义
NSString* name;
//.h中同时也要定义
extern NSString* name;
  • 对内的全局变量:没有用extern在.h中修饰的变量,仅定义在.m文件中让该变量只能在该类使用

优点:不管对象方法还是类方法都可以访问和修改全局静态变量,并且外部类无法调用静态变量,定义后只会存一份值,供所有对象使用,节省空间。跟全局静态变量一样,只是少了static修饰少了static特性。

缺点:存在的生命周期长,从定义直到程序结束。

建议:都跟全局静态变量都一样了,还需要用对内的全局变量吗?不用extern修饰就少了extern的特性,还不如用全局静态变量,至少能明确的知道static是对内使用的。

  • 对外的全局变量:除了该类,其他文件也可以访问该变量

优点:除了该类,其他文件也可以访问该变量

缺点:存在的生命周期长,从定义到程序结束,并且外部可以修改其值,出现错误不容易定位。

建议:使用全局变量的原因在于其对外的特性,但是其使用的方便性没有使用model的属性或宏来得方便。程序启动的时候会单独加载全局变量,同理与全局静态变量,少使用。

const常量

不同于变量,常量的值是固定不可变的,一般用于只读值

  • 优点:只可以读取值,不能修改。一般用于接口或者文字显示这种固定值。添加extern可以对外全局常量,任意位置都可以访问。
  • 缺点:存在的生命周期长,从定义直到程序结束。需要在.h .m中分别定义代码较多。
  • 建议:良好的编码习惯而言,少使用宏,多使用常量。因为常量声明是有明确类型的,而宏只是替换并不能进行类型判断。不够严谨。
//.h中定义extern
extern NSString *const name;
//.m中定义值
NSString *const name = @"123";//const声明部位不同,意义也不同。const定义的是其右边整体不可变。//*const name1定义的是 name1 不可变。 name1是指针。
//因此 不能通过修改name1而指向其他值。常规的const使用这个方法定义不可修改的值
NSString *const name1 = @"456";//const * name定义的是 * name不可变, 而*name指向的是@"789",
//也就是说@"789"这个内存地址的值不可变为其他值。
NSString const * name2 = @"789";
//但name指针可以指向其他值,所以该定义方式无法保证值的唯一性。
NSString *newName = @"222";
name2 = newName;
http://www.xdnf.cn/news/8735.html

相关文章:

  • 第2周 PINN核心技术揭秘: 如何用神经网络求解偏微分方程
  • 消息中间件之kafka
  • WSL 下面 Buildroot + QEMU 环境记录一下
  • [特殊字符] 使用增量同步+MQ机制将用户数据同步到Elasticsearch
  • Linux(6)——第一个小程序(进度条)
  • LeetCode 2942.查找包含给定字符的单词:使用库函数完成
  • 台式机安装新的固态硬盘后无显示
  • 【C语言练习】060. 使用指针操作字符串
  • Kotlin全栈工程师转型路径
  • Vue-创建应用/挂载应用/根组件模版-.vue单文件/应用配置
  • Cesium中根据不同条件设置3D Tiles样式
  • 【VBA 中GetOpenFilename】常用友好的人机交互文件全路径选择模式
  • 计算机视觉与深度学习 | 基于 YOLOv8 + BeautyGAN + CodeFormer + Face Parsing 实现简单的人脸美颜
  • 【来自纳米AI-大模型】ubuntu 24.04 登陆界面分辨率太高,内容显示得特别小 问题解决方案(亲测有效)
  • lua脚本学习笔记1:Vscode添加lua环境_lua基本语法
  • HarmonyOS赋能套件介绍
  • 开篇:MCP理论理解和学习
  • 元组可以比较大小吗?一次返回多个值?编程语言的元组?声明变量一定需要指定类型吗?
  • Ubuntu20.04 gr-gsm完整安装教程
  • Kanass V1.1.1版本发布,支持查看项目/迭代/事项进度
  • 剖析 Spring 中 @ResponseBody 原理与 Tomcat NIO 写事件(SelectionKey.OP_WRITE)的协作机制
  • MySQL分库分表
  • vue3中使用computed
  • Spark集群架构解析:核心组件与Standalone、YARN模式深度对比(AM,Container,Driver,Executor)
  • kafka之操作示例
  • 大文件上传,对接阿里oss采用前端分片技术。完成对应需求!
  • 【MySQL】第7节|Mysql锁机制与优化实践以及MVCC底层原理剖析
  • ubuntu 安装latex
  • 清除 Ubuntu 磁盘空间
  • 安卓开发用到的设计模式(2)结构型模式