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来创建、分配、释放、销毁堆空间。
堆分配算法
- 空闲链表:把堆中各个空闲的块按照链表的方式连接起来,遍历可以用来分配空间的块并把它拆分.
- 位图:讲整个堆划分为大量的块,当用户请求内存,总是分配整个块的空间给用户
- 对象池:如果每一次分配的空间都一样,可以按照每次请求分配的大小作为一个单位,把整个堆空间划分为小块。
9. 内存【《链接、装载与库》学习笔记】
http://blog.bluspace.ren/2025/12/11/9. 内存【《链接、装载与库》学习笔记】/