内存区域介绍

[!NOTE] The program code, global variables, and constant global variables are all stored in static segments, as these all have static lifetimes and known sizes at compile time.

If we look at the addresses printed by mexplore, we see that the global variables stored in are at relatively low memory addresses (around 0x60'0000 hexadecimal and 0x40'0000 hexadecimal), while the local variable is stored at a high address, close to 0x7fff'ffff'ffff (about 247), and the dynamically allocated character is stored in between (albeit closer to the static segments).

There is a reason for this placement: it allows both types of segments to grow without risk of getting in each other's way. In particular, the automatic-lifetime segment grows downwards as more local variables come into scope, while the dynamic-lifetime segment grows upwards. If they ever meet, your computer runs out of memory.

内存区域划分

在计算机中,程序运行时的内存布局通常分为多个区域,每个区域负责存储特定类型的数据。这种内存布局通常包括以下主要部分:

  1. 代码段(Text Segment):
    • 存储内容: 存放程序的可执行代码,也就是编译后的机器指令。该区域通常是只读的,以防止程序的代码被意外或恶意修改。
    • 特性: 常见操作系统将其标记为只读并可执行。
  2. 数据段(Data Segment):
    • 存储内容: 存放已初始化的全局变量和静态变量。这个段可以进一步分为两部分:
      • 已初始化数据段(Initialized Data Segment): 存储在编译时已初始化的全局和静态变量。
      • 未初始化数据段(BSS Segment,Block Started by Symbol): 存放未初始化的全局变量和静态变量。在程序开始执行时,BSS 段的内容会被初始化为零。
    • 特性: 数据段是可读写的。
  3. 堆(Heap dynamic-lifetime segment is called the heap:
    • 存储内容: 用于动态分配的内存块。malloccallocrealloc 等函数在运行时从堆中分配内存。堆的大小可以在运行时增长和缩小。
    • 特性: 堆区域通常从低地址向高地址扩展。
  4. 栈(Stack automatic-lifetime segment is called the stack.):
    • 存储内容: 用于存放函数的局部变量、函数参数和返回地址。当函数被调用时,会在栈上分配一个新的栈帧,用于存储该函数的局部数据。函数调用结束后,栈帧会被释放。
    • 特性: 栈区域通常从高地址向低地址扩展。栈的大小是有限的,过度使用栈空间(如过深的递归调用或大量局部变量)可能导致栈溢出。
  5. 常量段(Rodata Segment):
    • 存储内容: 存放只读数据,比如字符串常量和其他不变数据。这些数据通常在编译时确定并在运行时不会改变。
    • 特性: 常量段通常是只读的。
  6. 执行堆栈(Call Stack):
    • 存储内容: 特指用于存储每个线程的调用信息,包括函数调用的返回地址、局部变量和函数参数。执行堆栈与栈区域有些重叠的概念。
    • 特性: 递归调用或大量局部变量可能导致栈溢出。

内存布局示意图

典型的内存布局==从高地址到低地址==可以如下表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+--------------------+
| 栈 (Stack) |
+--------------------+
| 堆 (Heap) |
| (动态分配区) |
+--------------------+
| 未初始化数据段 (BSS) |
+--------------------+
| 已初始化数据段 (Data) |
+--------------------+
| 只读数据段 (Rodata) |
+--------------------+
| 代码段 (Text) |
+--------------------+
| 其他系统区域 (Other) |
+--------------------+
memory

在 C 语言中,变量根据其类型和作用域分布在程序的不同内存区域。以下是不同类型的变量及其存储位置的详细说明:

  1. 全局变量(Global Variables):
    • 定义: 在函数外部定义的变量,具有全局作用域,整个程序运行期间都可以访问。
    • 存储位置:
      • 已初始化的全局变量存储在数据段(Data Segment)的已初始化数据区域。
      • 未初始化的全局变量存储在BSS 段(Block Started by Symbol Segment),程序开始时 BSS 段的内容被初始化为零。
  2. 静态变量(Static Variables):
    • 定义: 使用 static 关键字修饰的变量。可以是全局或局部的,但在程序的生命周期内都只分配一次,并保留其值。
    • 存储位置:
      • 静态全局变量:与全局变量类似,已初始化的存储在数据段,未初始化的存储在 BSS 段。
      • 静态局部变量:尽管其作用域仅限于函数内,但其生命周期与程序相同,也存储在数据段或 BSS 段中。
  3. 常量变量(Constant Variables):
    • 定义: 使用 const 关键字修饰的变量,声明后不能更改其值。
    • 存储位置:
      • 常量全局变量:通常存储在只读数据段(Rodata Segment)。但如果常量是局部的,它可能存储在栈或寄存器中,具体取决于编译器优化。
      • 常量局部变量:通常在栈上分配,或者在某些情况下编译器可能将它们优化到寄存器中。
  4. 局部变量(Local Variables):
    • 定义: 在函数或块中定义的变量,只在其定义的作用域内有效。
    • 存储位置:
      • 通常存储在栈(Stack)中。函数调用时,局部变量在栈上分配空间,函数返回时这些空间被释放。
  5. 动态分配的内存:
    • 定义: 使用 malloccallocrealloc 等函数动态分配的内存。大小和数量在运行时决定。
    • 存储位置:
      • 存储在堆(Heap)中。堆内存的生命周期由程序员控制,需要手动释放(使用 free 函数),否则会导致内存泄漏。

总结

  • 代码段(Text Segment): 存放程序的可执行代码。
  • 数据段(Data Segment): 存放已初始化的全局变量和静态变量。
  • BSS 段(Block Started by Symbol Segment): 存放未初始化的全局变量和静态变量,程序开始时初始化为零。
  • 只读数据段(Rodata Segment): 存放常量数据和字符串常量。
  • 栈(Stack): 存放局部变量、函数参数和返回地址。
  • 堆(Heap): 存放动态分配的内存。

理解这些内存区域及其作用对于高效和安全的编程至关重要,特别是在涉及到动态内存管理、全局状态和并发问题时。


内存区域介绍
http://example.com/2024/09/07/内存区域介绍/
作者
JunBin Liang
发布于
2024年9月7日
许可协议