参考博客:iOS内存管理学习第一篇-内存五大区
3.1 OC特性之 内存五大区域
程序要想执行,第一步就需要 被加载到内存中
内存五大区域: 栈区,堆区,BSS段(静态区),常量区(数据段),代码段.
int main(int argc, const char * argv[]) {
// 局部变量是保存在栈区的
// 栈区变量出了作用域之后,就会被销毁
NSInteger i = 10;
NSLog(@"%zd", i);
// 赋值语句右侧,使用 new\alloc\init 方法创建的对象是保存在堆区的
// xinge 变量中,记录的是堆区的地址
// 在 OC 中,有一个内存管理机制,叫做 `ARC`,可以自动管理 OC 代码创建对象的生命周期
// 因此,在开发 OC 程序的时候,程序员通常不需要考虑内存释放的工作
LJXPerson *xinge = [LJXPerson new];
NSLog(@"%@", xinge);
return 0;
}
栈区 (stack [stæk]) : 由编译器自动分配释放
如果在程序中调用方法,会开启一个 " 栈帧 ".(这个栈帧可以理解为也是一块连续的区域)
栈帧的地址与之前的局部变量的地址不是连续的栈帧中记录实参地址,
以及方法内部的局部变量。方法执行完毕后,栈帧销毁(弹栈)
<<<这样每次执行完毕后,都弹栈释放内存,这样就会始终保证栈区占用的内存不会特别大>>
so-课外话->我们在开发的时候,如果每个方法都写的很短,同时每个方法声明的变量都很少.
这样做一定会节约内存
调用方法时栈区的工作原理
堆区 (heap [hiːp]): 由程序员分配释放,若程序员不释放,会出现内存泄漏
在开发 OC 程序的时候,程序员通常不需要考虑内存释放的工作。
但是如果在 OC 的代码中,如果使用到 C 语言分配空间的函数,则需要考虑释放内存
链表
来管理堆区中的内存分配情况开发要让变化控制在有限的范围内
这一部分因编译器、操作系统和具体的平台而有所不同。某些编译器和平台可能对内存布局和段的使用有自己的优化策略。因此,具体情况可能会有所变化,需要查看编译器和平台的文档以了解详细信息。
在Xcode13.3.1中,未初始化的全局变量和静态变量储存在静态区(.BSS段),初始化的全局变量和静态变量储存在数据区(.data段)。
需要注意的是,数据段通常是指静态区的一个子区域。在不同的系统和编译器中,这些术语可能有不同的定义和使用方式。有时候,数据段和静态区这两个术语也会被用来表示相同的内存区域。
验证:
验证代码:
// 设置两个全局变量,一个初始化,一个不初始化
int num1 = 1;
int num2;
int main(){
@autoreleasepool {
NSLog(@"num1 pointer = %p", &num1);
NSLog(@"num2 pointer = %p", &num2);
// 初始化num2
num2 = 2;
NSLog(@"init num2 pointer = %p", &num2);
// 设置两个静态变量,一个初始化,一个不初始化
static int sNum1 = 1;
static int sNum2;
NSLog(@"sNum1 pointer = %p", &sNum1);
NSLog(@"sNum2 pointer = %p", &sNum2);
sNum2 = 2;
NSLog(@"init sNum2 pointer = %p", &sNum2);
}
}
验证结果:
可知:
常量保存在常量区。
给前面的验证代码加一个常量:
// 设置两个全局变量,一个初始化,一个不初始化
int num1 = 1;
int num2;
int main(){
@autoreleasepool {
NSLog(@"num1 pointer = %p", &num1);
NSLog(@"num2 pointer = %p", &num2);
// 初始化num2
num2 = 2;
NSLog(@"init num2 pointer = %p", &num2);
// 设置两个静态变量,一个初始化,一个不初始化
static int sNum1 = 1;
static int sNum2;
NSLog(@"sNum1 pointer = %p", &sNum1);
NSLog(@"sNum2 pointer = %p", &sNum2);
sNum2 = 2;
NSLog(@"init sNum2 pointer = %p", &sNum2);
// 常量
const int cNum = 3;
NSLog(@"cNum pointer = %p", &cNum);
}
}
可知:
储存静态变量和全局变量,是否在一开始便初始化决定它们储存在.BSS段还是.data段,一经决定不再更改。
储存常量,不论是否初始化。
首先就是我们说到的TaggedPointer,推荐大家去看下官方提供的视频WWDC 2020,里面有详细解释为什么会使用到TaggedPointer,总结以下几点