【iOS开发】—— iOS内存管理

1. iOS内存分配区域

常说的五大内存分配区域,指的是栈区、堆区、常量区、全局区、代码区。

1.1 栈区

是由编译器自动分配并释放的,主要用来存储局部变量、函数的参数等,是一块连续的内存区域,遵循先进后出(FILO)原则。一般在运行时分配。它的分配由高地址空间向低地址空间分配。

优点:因为栈是由编译器自动分配并释放的,不会产生内存碎片,所以快速高效。
缺点:栈的内存大小有限制,数据不灵活。

例如:下图,创建两个变量,存放在栈区,地址是递减4。
在这里插入图片描述

1.2 堆区

堆区是由程序员手动管理。 主要用来存放动态分配的对象类型数据。是不连续的内存区域。在MRC环境下,由程序员手动释放,在ARC环境下,由编译器自动释放。一般在运行时分配。它的分配是从低地址空间向高地址空间分配。
优点:灵活方便,数据适应面广泛。
缺点:需手动管理,速度慢、容易产生内存碎片。

例如:下图,创建两个对象,存放在堆区,地址递增。
在这里插入图片描述

1.3 常量区

常量区存放的就是字符串常量和基本类型常量。在编译时分配,程序结束后回收。

1.4 全局区/静态区

全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在.data段,未初始化的全局变量和静态变量在相邻的.bss区域,在编译时分配,程序结束后由系统释放。

1.4.1 static静态变量
  1. 全局静态变量
    全局变量和全局静态变量的生命周期是一样的,都是在堆中的静态区,在整个工程执行期间内一直存在。
    特点如下:
    1)存储区:静态存储区没变(静态存储区在整个程序运行期间都存在);
    2)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。非静态全局变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。

好处:
1)不会被其他文件所访问,修改;
2)其他文件中可以使用相同名字的变量,不会发生冲突。

  1. 局部静态变量
    特点如下:
    1)存储区:有栈变为静态存储区rw data,生存期为整个源程序,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它;
    2)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
1.4.2 extern全局变量

==只是用来获取全局变量(包括静态全局变量)的值,不能用于定义变量。==先在当前文件查找有没有全局变量,没有找到,才会去其他文件查找。

全局静态变量与全局变量 其实本质上是没有区别的,只是存在修饰区别,一个static让其只能内部使用,一个extern让其可以外部使用。

1.5 代码区

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

2. iOS的编译链接

在一个程序从代码到执行程序过程里,存在四个阶段:预编译、编译、汇编、静态链接。

在这里插入图片描述

2.1 预处理

预处理也被称作预编译(Prepressing),是将main.m文件编译成mian.i文件,指令如下:

clang -E main.m -o main.i

处理源代码文件中以#开头的预编译指令。

2.2 编译

编译过程就是把上面的main.i文件进行:词法分析语法分析静态分析,优化生成相应的汇编代码,最终生成main.s文件。,指令如下:

clang -S main.i -o main.s
名称 处理过程
词法分析 把源代码的字符序列分割成一个个token(关键字、表示符、字面量、特殊符号),比如把标识符放到符号表里面。
语法分析 生成抽象语法树 AST,此时运算符号的优先级确定了;有些符号具有多重含义也确定了,比如“*”是乘号还是对指针取内容;表达式不合法、括号不匹配等,都会报错。
静态分析 分析类型声明和匹配问题。比如整型和字符串相加,肯定会报错。
中间语法生成 CodeGen根据AST自上向下逐步翻译成LLVM IR(连接着编译器前端和编译器后端),并且对在编译期就可以确定的表达式进行优化,比如代码里面的a=1+3,可以优化成a=4。(假如开启了bitcode)
目标代码生成与优化 根据中间语法生成依赖具体机器的汇编语言;并优化汇编语言。这个过程中,假如有变量且定义在同一个编译单元里,那么就给这个变量分配空间,确定变量的地址。假如变量或者函数不定义在这个编译单元里面,那就等到链接的时候才能确定地址。

2.3 汇编

这个过程就是把上面得到的main.s文件里面的汇编指令翻译成机器指令,最终生成等到main.o文件;指令如下:

clang -c main.s -o main.o

2.4 链接

这个过程就是将main.o编译成对应的Mach-O文件,也就是我们常说的可执行文件,指令如下:

clang main.o -o main

链接的本质就是把一个或多个目标文件和需要的库(静态库/动态库,如果需要的话)组合成一个文件(Mach-O可执行文件)。

3. 引用计数和MRC

在OC中,使用引用计数来进行内存管理。每个对象都有一个与其相对应的引用计数器,当持有一个对象,这个对象的引用计数就会递增;当这个对象的某个持有被释放,这个对象的引用计数就会递减。当这个对象的引用计数变为0,那么这个对象就会被系统回收。

当一个对象使用完没有释放,此时其引用计数永远大于1。该对象就会一直占用其分配在堆内存的空间,就会导致内存泄露。内存泄露到一定程度有可能导致内存溢出,进而导致程序崩溃。

3.1 内存管理的思考方式(四个基本法则)

3.1.1 自己生成的对象,自己持有

alloc\new\copy\mutableCopy 方法名开头来创建的对象意味着自己生成的对象只有自己持有。

id obj = [[NSObject alloc] init];
3.1.2 非自己生成的对象,自己也能持有

用 alloc / new / copy / mutableCopy 以外的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。(比如 NSMutableArray 类的 array方法),但是我们可以通过retain来手动持有对象。

//取得的对象存在但不持有
id obj = [NSMutableArray array];
//持有该对象
[obj retain];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值