美文网首页iOS 底层探索之路
iOS 底层探索:内存五大区

iOS 底层探索:内存五大区

作者: 欧德尔丶胡 | 来源:发表于2020-11-24 21:27 被阅读0次

    iOS 底层探索: 学习大纲 OC篇

    前言

    • 这篇开始探索内存管理,这篇主要介绍内存的分布的基础知识概念。

    一 、 内存五大区

    在iOS中,内存主要分为栈区、堆区、全局区、常量区、代码区五大区域。如下图所示

    针对4GB运存

    栈区(Stack)

    • 定义

      1. 栈是系统数据结构,其对应的进程或者线程是唯一的

      2. 栈是从高地址向低地址扩展扩展的数据结构

      3. 栈是一块连续的内存区域,遵循先进后出(FILO)原则

      4. 栈的地址空间在iOS中是以0x7开头

      5. 栈区一般在运行时分配

    • 存储

      栈区是由编译器自动分配并释放的,主要用来存储

      1. 局部变量

      2. 函数的参数,例如函数的隐藏参数(id self,SEL _cmd)

    • 优缺点

      1. 优点:因为栈是由编译器自动分配并释放的,不会产生内存碎片,所以快速高效

      2. 缺点:栈的内存大小有限制,数据不灵活

    注:

    • iOS主线程栈大小是1MB
    • 其他主线程是512KB
    • MAC只有8M

    缓冲区域

    • 定义 : 栈区和堆区中间有小块未使用的内存区域。用于给栈区和堆区之间创建一个缓冲区域

    • 溢出:到达缓冲区的数据向小缓冲区复制的过程中,由于没有注意小缓冲区的边界,导致小缓存区满了,从而覆盖了和小缓存区相邻内存区域的其他数据而引起的内存问题。(就像桶盛水,水多了,自然越界溢出来了。)

    堆区(Heap)

    • 定义
    1. 堆是从低地址向高地址扩展。

    2. 堆是不连续的内存区域,类似于链表结构(增删快,查找慢),遵循先进先出(FIFO)原则

    3. 堆的地址空间在iOS中是以0x6开头,其空间的分配总是动态的

    4. 堆区的分配一般是在运行时分配

    • 存储

      1. 堆区是由程序员动态分配和释放的,如果程序员不释放,程序结束后,可能由操作系统回收。
        主要用于存放 :
        a.OC中使用alloc或者 使用new开辟空间创建对象;
        b.C语言中使用malloc、calloc、realloc分配的空间,需要free释放,释放对象在堆区的内存,并将栈中的地址指针置空
    • 优缺点

      1. 优点:灵活方便,数据适应面广泛

      2. 缺点:需手动管理,速度慢、容易产生内存碎片

    注:
    当需要访问堆中内存时,一般需要先通过对象读取到栈区的指针地址,然后通过指针地址访问堆区

    野指针:提前释放了,查询时找不到内容
    内存泄露 :没有释放,一直占用内存
    过度释放:对已释放的对象进行release操作。

    全局静态区(.bss)

    1. 存放全局变量和静态变量
    2. 空间由系统管理。(程序启动时,开辟空间;程序结束时,回收空间;程序执行期间一直存在)在iOS中一般以0x1开头;
    3. static修饰的变量仅执行一次,生命周期为整个程序运行期

    常量区(.data)

    1. 存放常量(整型、字符型,浮点,字符串等),整个程序运行期不能被改变。

    2 .空间由系统管理,生命周期为整个程序运行期。在iOS中一般以0x1开头。

    代码区(即.text)

    • 定义:代码区是编译时分配主要用于存放程序运行时的代码,代码会被编译成二进制存进内存的,
      存放程序执行的CPU指令。(编译期将代码转换为CPU指令)

    内核区:

    • 交给系统处理的内核区域, 以4GB手机为例 ,图中高地址 0xc0000000 = 1024 x 1024 x 1024 x 3 总共占3GB,还有1GB就是留给内核区使用的。
    • 0x0040000 ~ 0之间的保留
    拓展

    defineconst区别:

    define: 宏。编译期不会进行语法识别,没有类型。编译期会分配内存。每次使用都会进行宏替换和开辟内存。

    const: 常量。编译期会进行语法识别,需要指定类型。编译期不会分配内存,仅在第一次使用时,开辟内存并记录内存地址。后续调用时不会开辟内存,直接返回记录的内存地址。效率更快。内存占用更少。

    内存验证

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

    - (void)test {
        
        NSInteger i = 666;
        NSLog(@"NSInteger i -> 内存地址:%p", &i); // 【局部变量】 栈区
    
        NSString * name = @"QWERDF";
        NSLog(@"NSString name -> 内存地址: %p", name); // 【字符串内容】 存放在常量区
        NSLog(@"NSString name -> 指针地址: %p", &name);// 【局部变量name的指针】 存放在栈区
        
        NSObject * objc = [NSObject new];
        NSLog(@"NSObject objc -> 内存地址: %p", objc);// 【对象的内容】 存放在堆区
        NSLog(@"NSObject objc -> 指针地址: %p", &objc);//【对象的指针】 存放在栈区
    }
    

    打印结果: (0x7开头: 栈区 、 0x1开头: 常量区、 0x6开头: 堆区)

    2020-11-02 11:19:39.121235+0800 001---- 内存验证[5104:87115] NSInteger i -> 内存地址:0x7ffeeb3e0668 (栈区)
    2020-11-02 11:19:39.124740+0800 001---- 内存验证[5104:87115] NSString name -> 内存地址: 0x10481f0e0(常量区)
    2020-11-02 11:19:39.128252+0800 001---- 内存验证[5104:87115] NSString name -> 指针地址: 0x7ffeeb3e0660(栈区)
    2020-11-02 11:19:39.143804+0800 001---- 内存验证[5104:87115] NSObject objc -> 内存地址: 0x600002fc07d0(堆区)
    2020-11-02 11:19:39.145034+0800 001---- 内存验证[5104:87115] NSObject objc -> 指针地址: 0x7ffeeb3e0658(栈区)
    

    相关文章

      网友评论

        本文标题:iOS 底层探索:内存五大区

        本文链接:https://www.haomeiwen.com/subject/iuvwiktx.html