📜  堆栈与堆内存分配(1)

📅  最后修改于: 2023-12-03 15:37:49.712000             🧑  作者: Mango

堆栈与堆内存分配

在计算机中, 当程序运行时, 所需的内存分为两个部分, 一部分是由操作系统管理的静态内存空间(如代码段, 数据段等等), 另一部分则是由程序从操作系统请求的动态内存空间.

栈是一种特殊的数据结构, 其特殊之处在于它的数据结构只能在其顶部进行插入或删除操作. 栈遵循先进后出原则.

在程序中, 栈用来存储函数的参数, 函数调用时的现场(函数的返回地址, 函数调用时的数据等等), 以及一些本地变量等.

栈的特点包括:

  • 栈是一个后进先出(LIFO)的数据结构
  • 栈中仅能访问栈顶的元素
  • 容量在创建时确定

对栈的操作包括:

  • 入栈(Push): 向栈顶插入一个元素
  • 出栈(Pop): 弹出栈顶元素
  • 查看栈顶元素(Peek): 查看栈顶元素, 但并不弹出

堆是一片零散的内存空间, 在程序运行时, 由操作系统动态分配, 用于存储程序运行时的动态数据, 例如变量, 对象等.

堆的特点包括:

  • 堆中的内存空间是动态分配的
  • 堆中的内存可以被多个线程、函数共享
  • 堆可以动态增长

由于堆的特点, 大部分语言中的内存管理都采用堆内存分配.

堆内存分配常用API:

  • malloc: 分配指定大小的内存空间
  • calloc: 分配指定大小的内存空间, 并初始化为0
  • realloc: 重新分配已经分配的内存空间
  • free: 释放已经分配的内存空间

值得注意的是, 堆内存的释放必须由程序员手动管理, 必须在程序不再使用该内存时进行释放, 否则会导致内存泄漏.

栈和堆的选择

栈和堆都是程序中用来存储数据的空间, 在选择使用栈还是堆时, 需要考虑以下因素:

  • 地址: 栈中的数据实际上是存储在物理内存中的数据, 所以它们的地址是自动分配的. 堆中的数据则是动态分配的, 其地址需要手动分配和释放.
  • 性能: 栈的效率比堆高, 因为栈中的数据是连续存储的, 所以栈存取数据时比堆快.
  • 大小: 栈的大小是固定的, 而堆则可以动态增长.

在实际编程中, 需要根据具体情况选择使用栈还是堆, 以达到最佳性能和稳定性.

示例代码

以下是C语言中堆和栈的使用示例:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int x = 10; // x在栈中分配
    int *y = NULL; // 定义一个指向整型变量的指针, 但暂未进行初始化
    y = (int *) malloc(sizeof(int)); // 在堆中申请空间来存储一个整型变量的大小, 并将其地址赋给y
    *y = 88; // 在y指向的地址处存储第一个整数
    printf("x=%d\n", x);
    printf("*y=%d\n", *y);
    free(y); // 释放y指向的地址处的堆空间
    return 0;
}
上述代码定义了一个整型变量x, 并在栈中为其分配了内存空间. 同时, 代码也定义了一个指向整型变量的指针y, 并通过malloc函数在堆中为其分配内存空间. 其中, sizeof(int)返回sizeof关键字计算的整型变量大小字节, 调用free函数释放y指向的地址处的堆空间.

栈中分配的变量x在程序离开作用域时, 其内存空间会被系统回收, 而堆中分配的变量需要手动调用free函数来进行释放, 否则就会导致内存泄漏.