9. 内存【《链接、装载与库》学习笔记】

程序的内存布局

平坦(flat)的内存布局:整个内存是一个同意的地址空间,可以使用指针访问任意内存位置。

os会把高地址的1~2GB分配给内核,剩下的哦那关键被称为用户空间。分为如下默认的区域:

  • 栈:用于维护函数调用的上下文,通常在用户空间的最高地址处分配。通常几MB。
  • 堆:用来容纳应用程序动态分配的内存区域,一般存在栈的下方。通常几十、几百MB。
  • 可执行文件映像:存储可执行文件在内存里的映像
  • 保留区:不是一个单一的内存区域,而是对内存中收到保护而禁止访问的内存区域的总称(比如极小的地址)

栈与调用惯例

在经典的操作系统里,栈总是向下增长的,在i386下,栈顶由称为esp的寄存器进行定位。压栈的操作使栈顶的地址减小,弹出的操作使栈顶地址增大。

栈保存了一个函数调用所需要的维护信息,这常常被称为堆栈帧(Stack Frame)或活动记录(Activate Record)。堆栈帧一般包括如下几方面的内容:

  • 函数的返回地址和参数
  • 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量
  • 保存的上下文:包括在函数调用前后需要保持不变的寄存器。

debug模式会把所有分配出来的栈空间的每一个字节都初始化成0xCC

函数调用方和被调用方对于函数如何调用有一个明确的约定,这样的约定叫调用惯例(Calling Convention),一般规定如下内容:

  • 函数参数的传递顺序和方式
  • 栈的维护方式
  • 名字修饰策略

函数返回值传递

对于小于4字节的,使用eax寄存器返回,对于大于4B的,eax寄存器储存一个指向返回值的指针

C++应该尽量减少返回值传递大对象。

堆与内存管理

堆是一块巨大的内存空间,常常占据整个虚拟哦那关键的绝大部分。程序可以请求一块连续内存并自由使用。

运行时库管理堆空间,向操作系统“批发”,操作系统再向程序“零售”。

Linux进程堆管理

brk()设置进程数据段的结束地址
mmap()向操作系统申请一段地址空间,它可以映射到某个文件,也可以成为匿名空间。

Windows进程堆管理

在Windows种,这个算法的实现位于堆管理器(Heap Manager),提供4个API来创建、分配、释放、销毁堆空间。

堆分配算法

  1. 空闲链表:把堆中各个空闲的块按照链表的方式连接起来,遍历可以用来分配空间的块并把它拆分.
  2. 位图:讲整个堆划分为大量的块,当用户请求内存,总是分配整个块的空间给用户
  3. 对象池:如果每一次分配的空间都一样,可以按照每次请求分配的大小作为一个单位,把整个堆空间划分为小块。

9. 内存【《链接、装载与库》学习笔记】
http://blog.bluspace.ren/2025/12/11/9. 内存【《链接、装载与库》学习笔记】/
作者
Blauter
发布于
2025年12月11日
许可协议