美文网首页
iOS 内存管理 (1):堆栈

iOS 内存管理 (1):堆栈

作者: 知礼账本 | 来源:发表于2020-03-16 16:32 被阅读0次

    栈:

    栈是线程执行过程中存放在低地址位缓存数据的一个内存块,其读写速度是快的。一个线程对应一个这样的内存块,栈是先进后出的结构,其数据大小是固定的,因此栈中不存在两个变量间有“内存间隙”。由于这个特性也不需要自己手动释放内存。栈的大小比堆小,一旦一个函数执行的时候它需要的参数就会被推进栈中,一旦函数执行完后这个函数和他的参数就会被推出栈中,这样确保了栈的内存回收。栈可能会有栈溢出的问题,如果出现了栈溢出(1):只要栈的剩余空间大于申请空间,系统将为程序提供内存,否则将报异常提示(overflow)。那么程序将会崩溃。

    栈中存储的每一个函数在执行的时候都会向操作系统索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和释放,内存随着函数的运行分配,随着函数的结束而释放,由系统自动完成。栈是向低地址扩展的数据结构,是一块连续的内存的区域。是栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数 ) ,如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

    堆:

    堆是程序执行过程中的公共内存区域,每一个程序有一个唯一的堆,这个堆可以由这个程序的多个线程共同访问。堆的大小是可以动态分配的。一般堆分配内存通过alloc,copy等关键字来修饰。

    操作系统有一个记录空闲内存地址的链表。当系统收到内存的申请时会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中

    堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    堆栈相关

    1、栈变量 堆变量:针对变量的内存位置,堆变量就是内存在堆中的变量,栈变量就是内存在栈中的变量。

    2、block变量是堆变量还是栈变量:block对象变量通常在初始化的过程中是分配在栈中的,但是由于block可以作为参数传递,这个传递的过程是有状态的,但是栈并不会负责帮你把block retain住,所以当对一个block对象在一个作用域传递到另一个作用域的时候,其实系统会把这个block保存到堆中。arc中会系统会自动保存,不是arc的话就要自己做处理,否则会出现异常(2)。这种传递包括作用域发生改变后的变量传递和属性赋值。

    其他分区

    1、 全局区/静态区(static):初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。

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

    3、代码区:存放函数的二进制代码。

    示例:

    int a = 0; // 全局初始化区域
    char *p1; // 全局非初始化区域
    main()
    {
        int   b; // 栈
        char s[] = "abc"; //栈
        char   *p2; // 栈
        char   *p3   =   "123456"; // p3在栈中, 123456在常量区
        static   int   c   = 0;    // 全局初始化区
        p1   =   (char   *)malloc(10); // 堆
        p2   =   (char   *)malloc(20); // 堆
        
        strcpy(p1,   "123456"); // 123456在常量区,编译器h可能会将它与p3指向的“123456”优化成一个地方
    }
    

    图示:

    image

    相关文章

      网友评论

          本文标题:iOS 内存管理 (1):堆栈

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