C程序的内存布局详细指南

2021年3月13日16:20:21 发表评论 827 次浏览

C程序的典型内存表示包括以下部分。

1.文字区隔(常量)

2.初始化数据段

3.未初始化的数据段

4.堆叠(stack)

5.堆(heap)

C程序的内存布局1

正在运行的进程的典型内存布局

1.文字区隔:

文本段, 也称为代码段或简称为文本, 是目标文件或内存中程序的一部分, 其中包含可执行指令。

作为内存区域, 可以在堆或堆栈下方放置一个文本段, 以防止堆和堆栈溢出覆盖它。

通常, 文本段是可共享的, 因此对于频繁执行的程序(例如, 文本编辑器, C编译器, shell等), 仅一个副本需要存储在内存中。另外, 文本段通常是只读的, 以防止程序意外修改其指令。

2.初始化的数据段:

初始化的数据段, 通常简称为数据段。数据段是程序的虚拟地址空间的一部分, 其中包含由程序员初始化的全局变量和静态变量。

请注意, 数据段不是只读的, 因为可以在运行时更改变量的值。

该段可以进一步分为初始化的只读区域和初始化的读写区域。

例如, 在C中由char s [] =" hello world"定义的全局字符串以及在main(即global)外部的int debug = 1之类的C语句将存储在初始化的读写区域中。像const char * string =" hello world"这样的全局C语句使字符串文字" hello world"存储在初始化的只读区域中, 而字符指针变量字符串存储在初始化的读写区域中。

例如:静态int i = 10将存储在数据段中, 而全局int i = 10也将存储在数据段中

3.未初始化的数据段:

未初始化的数据段, 通常称为" bss"段, 以一个古老的汇编程序运算符命名, 代表"以符号开头的块"。在程序开始执行之前, 内核将该段中的数据初始化为算术0。

未初始化的数据从数据段的末尾开始, 包含所有初始化为零或在源代码中没有显式初始化的全局变量和静态变量。

例如, 一个声明为static int i的变量;将包含在BSS细分中。

例如, 一个声明为int j的全局变量;将包含在BSS细分中。

4.堆栈:

传统上, 堆栈区与堆区相邻, 并且方向相反。当堆栈指针遇到堆指针时, 可用内存就用完了。 (利用现代的大地址空间和虚拟内存技术, 它们可以放置在几乎任何地方, 但它们通常仍会朝相反的方向生长。)

堆栈区域包含程序堆栈(一种LIFO结构), 通常位于内存的较高部分。在标准PC x86计算机体系结构上, 它向地址零增长;在其他一些架构上, 它的发展方向相反。 "堆栈指针"寄存器跟踪堆栈的顶部。每次将值"推入"堆栈时都会对其进行调整。为一个函数调用推入的一组值称为"堆栈帧";堆栈帧至少包含一个返回地址。

堆栈, 用于存储自动变量, 以及每次调用函数时保存的信息。每次调用函数时, 返回位置的地址和有关调用者环境的某些信息(例如某些机器寄存器)都保存在堆栈中。然后, 新调用的函数在堆栈上为其自动和临时变量分配空间。这就是C中的递归函数如何工作的方式。每次递归函数调用自身时, 都会使用一个新的堆栈框架, 因此一组变量不会干扰该函数另一个实例的变量。

5.堆:

堆是通常进行动态内存分配的段。

堆区域从BSS段的末尾开始, 并从那里扩展到更大的地址。堆区域由malloc, realloc和free管理, 它们可以使用brk和sbrk系统调用来调整其大小(请注意使用不需要brk / sbrk和单个"堆区"来满足malloc / realloc / free的约定;它们也可以使用mmap来实现, 以将虚拟内存的潜在不连续区域保留到进程的虚拟地址空间中) 。堆区域由进程中的所有共享库和动态加载的模块共享。

例子。

size(1)命令报告文本, 数据和bss段的大小(以字节为单位)。 (有关更多详细信息, 请参考size(1)的手册页)

1.检查以下简单的C程序

#include <stdio.h>
  
int main( void )
{
     return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960        248          8       1216        4c0    memory-layout

2.让我们在程序中添加一个全局变量, 现在检查bss的大小(以红色突出显示)。

#include <stdio.h>
  
int global; /* Uninitialized variable stored in bss*/
  
int main( void )
{
     return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         12       1220        4c4    memory-layout

3.让我们添加一个静态变量, 该变量也存储在bss中。

#include <stdio.h>
  
int global; /* Uninitialized variable stored in bss*/
  
int main( void )
{
     static int i; /* Uninitialized static variable stored in bss */
     return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         16       1224        4c8    memory-layout

4.让我们初始化静态变量, 然后将其存储在数据段(DS)中

#include <stdio.h>
  
int global; /* Uninitialized variable stored in bss*/
  
int main( void )
{
     static int i = 100; /* Initialized static variable stored in DS*/
     return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         252         12       1224        4c8    memory-layout

5.让我们初始化全局变量, 然后将其存储在数据段(DS)中

#include <stdio.h>
  
int global = 10; /* initialized global variable stored in DS*/
  
int main( void )
{
     static int i = 100; /* Initialized static variable stored in DS*/
     return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         256          8       1224        4c8    memory-layout
木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: