• 【iOS】-- 内存五大分区


    内存五大分区

    内存五大分区:
    栈区(系统管理的地方),堆区(程序员管理的地方),常量区,全局区(静态区),代码区。
    在这里插入图片描述

    1.栈区

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

    优点:

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

    下面来看一个例子:

    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段)。

    //举例
    	int a; //未初始化的 .bss
        int a = 10; //初始化的 .data
    

    4.常量区

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

    5.代码区

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

    验证

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

    - (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);  
    }
    
    

    运行结果如下:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a525e73e363e4874b994fdf88d29daa5.png

    • 对于局部变量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中分别定义代码较多。

  • 相关阅读:
    【C#二开业务冠邑】通过界面查看数据来源
    计算机体系结构:不同改进方案的性价比计算
    外业精灵,在水土流失监测野外调查工作中的应用
    支持homekit的智能生态有哪些?
    sh、bash 和 dash 几种 shell 的区别是什么?
    探讨代理IP与Socks5代理在跨界电商中的网络安全应用
    IP-guard Web系统远程命令执行漏洞说明
    html网页设计大学生作业成品——公益校园网站设计与实现(HTML+CSS+JavaScript)
    039-第三代软件开发-PDF阅读器
    电厂锅炉四管爆管原因汇总
  • 原文地址:https://blog.csdn.net/qq_72437394/article/details/138586032