iOS循序渐进篇三:iOS内存组成情况介绍

2020-12-27  本文已影响0人  song91425

1、前言

      iOS的内存可分为五大块:栈区、堆区、常量区、全局区(静态区)、代码区。

1.1 堆区, 栈区, 常量区的内存首地址:

栈区 : 0x7xxxx
堆区 : 0x6xxxx
常量区和静态变量区 : 0x1xxxx

1.2 iOS内存分区可视化

image.png

如下面的代码

   int a = 0;//0存放在初始化的全局区(数据区)
   NSString *str;//未初始化区(BSS区)str地址是在栈,但是str的指向地址是全局区
   static NSString *staticString = @"kep";//静态初始化全局区 staticString的地址是在全局区,它的指向也是全局区
   @implementation ViewController

   - (void)viewDidLoad {
       [super viewDidLoad];
       int b=1;//在栈上
       static int c =123; // 分配在静态区
       const NSString * cStr = @"lss"; // cStr分配在栈上,它的指向是常量区
       static NSString *sStr = @"lss2";  // sStr 分配在静态区,它的指向也是常量区
       NSString * str = @"lss3"; //str分配在栈上,指向的是常量区
       NSMutableArray * arr= [NSMutableArray array ]; //arr在栈中,指向堆区的地址

       //  定义一个加法计算方法
       int add = [self addWithNumber:2 andOtherNumber:3]; // add存在栈区
       NSLog(@"b内存地址:%p",&b); // b内存地址:0x7ffeeba5013c
       NSLog(@"c内存地址:%p",&c); // c内存地址:0x1041fde80
       NSLog(@"cStr内存地址:%p",&cStr);// cStr内存地址:0x7ffeeba50130
       NSLog(@"cStr指向的内存地址:%p",cStr);// cStr指向的内存地址:0x1041eb310

       NSLog(@"sStr内存地址:%p",&sStr);// sStr内存地址:0x1041fde88
       NSLog(@"sStr指向的内存地址:%p",sStr);// sStr指向的内存地址:0x1041eb330

       NSLog(@"arr内存地址:%p",&arr);// arr内存地址:0x7ffeeba50120
       NSLog(@"arr指向的内存地址:%p",arr);// arr指向的内存地址:0x600003bd1e00

       NSLog(@"add内存地址:%p",&add);//add内存地址:0x7ffeeba5011c

       // 全局区
       NSLog(@"a内存地址:%p",&a);// a内存地址:0x1041fe628
       NSLog(@"str内存地址:%p",&str);// str内存地址:0x7ffeeba50128
       NSLog(@"str指向的内存地址:%p",str);// str指向的内存地址:0x1041eb350

       NSLog(@"staticString内存地址:%p",&staticString);// staticString内存地址:0x1041fde78
       NSLog(@"staticString指向的内存地址:%p",staticString);// staticString指向的内存地址:0x1041eb2f0
   }
   - (int) addWithNumber:(int)num1 andOtherNumber:(int)num2{
       NSLog(@"num1内存地址:%p",&num1);// num1内存地址:0x7ffeeba500cc
       return num1 + num2;//存在栈区
   }
1.1 栈区

      它是由编译器自动分配和管理的,函数的执行对应着栈的出栈和进栈,所以随着函数执行结束,栈所占内存也将会被释放掉。所以对栈的内存管理,由系统直接完成。栈区分配的内存是连续的,并且由编译器自动分配释放。具体一点就是创建的局部变量,存放函数的参数值等,也就是对应{}里面的对象。在{}括号里除了通过alloc/new/copy/mutableCopy申请的对象(对象存在堆区)或者通过static/const申请的对象(对象存放在全局区/常量区),其他对象都是存放在栈上,包括{}里调用的函数的返回值。注意由const声明的指针是存放在栈上的,指针的指向才是常量区。

1.2 堆区

      这个区域是iOS的ARC作用的区域,我们在代码中通过alloc/new/copy/mutableCopy的声明对象它是存放在堆区,但是指向它的指针存放在栈区,堆区分配的内存是非连续的,一般由程序员分配释放,若程序员不释放,待程序结束时,由系统回收。
NSObject *o = [NSObject new]; // o指针分配在栈区,[NSObject new]创建的对象分配在堆区,o指针指向堆区的对象
      在iOS中ARC管理的是OC对象,那么问题来了,什么是OC对象?从底层上讲OC对象是指在堆区存储的数据结构。从iOS层次上来看,凡是首地址是*isa的指针,就可以看成OC对象,比如id、NSObject在堆区开辟的空间。比如:
                                          NSObject *obj = [NSObject alloc];
       我们通常认为obj是一个对象,但是严格来说obj是一个指针, [NSObject alloc] 才是一个对象 ,[NSObject alloc] 执行完后,会在堆上开辟一个内存,这块内存里的东西才叫做对象,而obj只是一个指针,这个指针存储的是这块内存的首地址,它类似字典的索引页,通过索引页所指的页找到想要的对象。所以说obj是一个也是可以的,它就代表着在堆里的那块内存

1.3 常量区

       这块区域是iOS基础类型和字符串常量存放区域。比如通过int、float、double声明的常量和const声明的常量。这个区待程序执行结束时,由系统释放。

int a = 0; // 0数值在常量区存储,a存在栈区
float b =2;// 2数值在常量区存储,b存在栈区
const NSString *str = @"lss"; // 常量区

1.4 全局区/静态区

       全局区/静态区存放的是静态变量,静态全局变量,以及全局变量。这块内存可以细分为数据区和BBS区,它们的区别在于声明的对象是否初始化,如果初始化那就分配在数据区,未初始化就分配在BBS区。这个区待程序执行结束时,由系统释放。

int a=0; // 初始化的全局变量(数据区)
NSString *str;// 未初始化的全局变量(BBS区)
static NSString *string = @"123"; // 初始化全局静态变量(数据区)
int main(){
// 省略多行代码
};

1.5 代码区

       代码段是用来存放可执行文件的操作指令(存放函数的二进制代码),也就是说是它是可执行程序在内存种的镜像。代码段需要防止在运行时被非法修改,所以只准读取操作,而不允许写入(修改)操作——它是不可写的。这个区待程序执行结束时,由系统释放。参考

上一篇下一篇

猜你喜欢

热点阅读