【iOS】-- 内存五大分区

【iOS】-- 内存五大分区

内存五大分区

内存五大分区:

栈区(系统管理的地方),堆区(程序员管理的地方),常量区,全局区(静态区),代码区。

1.栈区

栈区(stack): 是一段连续的内存区域,从高地址向低地址存储,遵循先进后出(FILO)原则 。 一般在运行时进行分配,内存空间由系统管理 ,变量过了作用域范围后内存便会自动释放。参数、函数、局部变量都放在栈区。参数入栈是从前往后入栈;而结构体入栈是从后往前入栈。

优点:

  • 栈是系统数据结构,对应线程/进程是唯一的。
  • 快速高效,缺点是有限制,数据不灵活。[先进后出]
  • 栈空间分静态分配和动态分配两种。
  • 静态分配是编译器完成的,比如自动变量(auto)的分配。
  • 动态分配由alloc函数完成。
  • 栈的动态分配无需释放(是自动的),也就没有释放函数。

下面来看一个例子:

objectivec 复制代码
NSObject *obj = [NSObject new];

obj是一个指针变量,不是一个对象,存储在栈区,真正的创建对象,new做的事情有四步:

  1. 在堆内存中申请一块合适大小的空间。
  2. 在申请的这块空间中根据类的模板创建对象。
  3. 初始化对象的属性,为对象的属性赋默认值:
    • 如果属性的类型是基本数据类型,就赋值为0。
    • C指针类型NULL。
    • OC指针类型 nil。
  4. 返回这个对象在堆空间的地址。
    将这个地址返回赋值给obj指针,该指针指向了堆空间中的NSObject对象。

2.堆区

堆区(heap): 由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如变量通过new、alloc、malloc、realloc分配的内存块就存放在堆区。

堆向高地址扩展的数据结构,是不连续的内存区域。 程序员负责在何时释放内存,在ARC程序中,计数器为0的时候,在当次的runloop结束后,释放掉内存。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。

对于堆来讲,频繁的new/delete势必会造成内存空间的不连续性,从而造成大量的碎片 ,使程序效率降低。

优点:

  • 灵活方便,数据适应面广泛,但是效率有一定降低。
  • 堆是函数库内部数据结构,不一定唯一。
  • 不同堆分配的内存无法互相操作。
  • 堆空间的分配总是动态的。

3.全局区

全局区(静态区) (static): 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。

全局区又可分为未初始化全局区(BSS段)和初始化全局区(DATA段)。

objectivec 复制代码
//举例
	int a; //未初始化的 .bss
    int a = 10; //初始化的 .data

4.常量区

文字常量区: 存放常量字符串,程序结束后由系统释放

该区是编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放。
存放常量:整型、字符型、浮点、字符串等。

5.代码区

程序代码区: 用来存放函数的二进制代码。

代码段需要防止在运行时被非法修改,所以只允许读取操作,而不允许写入操作。

验证

运行下面一段代码,看看变量在内存中是如何分配

objectivec 复制代码
- (void)test{
    
    NSInteger i = 123;
    NSLog(@"i的内存地址:%p", &i);
    
    NSString *string = @"CJL";
    NSLog(@"string的内存地址:%p", string);
    NSLog(@"&string的内存地址:%p", &string);
    
    NSObject *obj = [[NSObject alloc] init];
    NSLog(@"obj的内存地址:%p", obj);
    NSLog(@"&obj的内存地址:%p", &obj);  
}

运行结果如下:

  • 对于局部变量i,从地址可以看出是0x7开头,所以i存放在栈区
  • 对于字符串对象string,分别打印了string的对象地址 和 string对象的指针地址
    • string的对象地址是以0x1开头,说明是存放在常量区
    • string对象的指针地址是以0x7开头,说明是存放在栈区
  • 对于alloc创建的对象obj,分别打印了obj的对象地址 和 obj对象的指针地址(可以参考前文的汇总图)
    • obj的对象地址是以0x6开头,说明是存放在堆区
    • obj对象的指针地址是以0x7开头,说明是存放在栈区。

static、extern、const关键字比较

1.static关键字

static关键字的作用:

  1. 可以修饰局部变量,将局部变量存储到静态存储区。
  2. 可以修饰全局变量,限定全局变量只能在当前源文件中访问。
  3. 可以修饰函数,限定函数只能在当前源文件中调用。

全局静态变量

优点:无论是类方法还是实例方法都可以访问和修改全局静态变量,外部方法无法调用,供所用对象调用。

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

局部静态变量

优点:定义后只保存一份值,每次调用的时候,没有重新创建,节省空间,只能在该局部代码中使用。

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

2.extern关键字

全局变量分为两种:

对内的全局变量

优点:无论是类方法还是实例方法都可以访问和修改全局静态变量,外部方法无法调用,总所有对象使用

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

对外的全局变量

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

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

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

3.const关键字

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

优点:只可以读取值,不能修改。一般用于接口或者文字显示这种固定值。添加extern可以对外全局常量,任意位置都可以访问。

缺点:存在的生命周期长,从定义直到程序结束。需要在.h .m中分别定义代码较多。

相关推荐
鹏多多12 分钟前
Flutter下拉刷新上拉加载侧拉刷新插件:easy_refresh全面使用指南
android·前端·ios
青花锁21 分钟前
Mac电脑安装Docker
macos·docker·容器
驱动探索者1 小时前
[缩略语大全]之[IOS]篇
ios
kkk_皮蛋21 小时前
在移动端使用 WebRTC (Android/iOS)
android·ios·webrtc
Swift社区1 天前
如何在 SwiftUI 中对 CoreImage 滤镜做实时预览
ios·swiftui·cocoa
李玮豪Jimmy1 天前
MacOS 上安装 JDK 并实现多版本灵活切换
macos
mixboot1 天前
VoxCPM 1.5.0 macOS
macos·voxcpm
甜可儿1 天前
mac环境安装不同版本maven
java·macos·maven
bl4ckpe4ch1 天前
从零开始Mac OS 开荒整理笔记
笔记·macos·开荒
ipad协议开发1 天前
企业微信iPad协议的开发进程
ios·企业微信·ipad