操作系统中的栈和堆

注:这里所说的堆和栈与数据结构中的堆和栈不是一回事。

我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构:
2016-07-27_09:30:05.jpg

  • 栈区(stack):由系统自动分配,一般存放函数参数值、局部变量的值等。由编译器自动创建与释放。其操作方式类似于数据结构中的栈,即后进先出、先进后出的原则。

    例如:在函数中申明一个局部变量int b;系统自动在栈中为b开辟空间。

  • 堆区(heap):一般由程序员申请并指明大小,最终也由程序员释放。如果程序员不释放,程序结束时可能会由OS回收。对于堆区的管理是采用链表式管理的,操作系统有一个记录空闲内存地址的链表,当接收到程序分配内存的申请时,操作系统就会遍历该链表,遍历到一个记录的内存地址大于申请内存的链表节点,并将该节点从该链表中删除,然后将该节点记录的内存地址分配给程序。

    例如:在C中malloc函数

    1
    2
    char p1;
    p1 = (char )malloc(10);

    但是p1本身是在栈中的。

    链表:是一种常见的基础数据结构,一般分为单向链表、双向链表、循环链表。以下为单向链表的结构图:
    2016-07-27_09:34:32.jpg

    单向链表是链表中最简单的一种,它包含两个区域,一个信息域和一个指针域。信息域保存或显示关于节点的信息,指针域储存下一个节点的地址。

    上述的空闲内存地址链表的信息域保存的就是空闲内存的地址。

  • 全局区/静态区:顾名思义,全局变量和静态变量存储在这个区域。只不过初始化的全局变量和静态变量存储在一块,未初始化的全局变量和静态变量存储在一块。程序结束后由系统释放。
  • 文字常量区:这个区域主要存储字符串常量。程序结束后由系统释放。
  • 程序代码区:这个区域主要存放函数体的二进制代码。

    下面举一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //main.cpp
    int a = 0; // 全局初始化区
    char *p1; // 全局未初始化区
    main {
    int b; // 栈
    char s[] = "abc"; // 栈
    char *p2; // 栈
    char *p3 = "123456"; // 123456\0在常量区,p3在栈上
    static int c =0// 全局静态初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在堆区
    strcpy(p1, "123456"); // 123456\0在常量区,这个函数的作用是将"123456" 这串字符串复制一份放在p1申请的10个字节的堆区域中。
    // p3指向的"123456"与这里的"123456"可能会被编译器优化成一个地址。
    }
Jackson wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
如果你觉得我的文章还不错,欢迎打赏~