在多任务系统中,每个进程都运行在自己的虚拟地址空间上,32为模式下它是一个4G的内存地址块,在Linux系统下主要分为1G内核空间和3G用户空间,而在Windows系统下,内核空间和用户空间的划分比例为2:2.
在Linux系统下虚拟地址空间布局如下图所示:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TUaJXOtFmZSNzY2J0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyczM4EDN1kTM3EzNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
位于虚拟地址空间最低部分为保留区,未赋予物理地址
.text 为代码段用来存放程序执行代码
.data段称为数据段,用来存放程序中已初始化并且初始化不为0的全局变量和静态局部变量,数据段属于静态内存分配,可读可写
.bss段又称未初始化段,用来存放未初始化或者初始化为0的全局变量和静态局部变量
数据段与BSS段的区别如下:
1) BSS段不占用物理文件尺寸,但占用内存空间;数据段占用物理文件,也占用内存空间。
对于大型数组如int ar0[10000] = {1, 2, 3, ...}和int ar1[10000],ar1放在BSS段,只记录共有10000*4个字节需要初始化为0,而不是像ar0那样记录每个数据1、2、3...,此时BSS为目标文件所节省的磁盘空间相当可观。
2) 当程序读取数据段的数据时,系统会出发缺页故障,从而分配相应的物理内存;当程序读取BSS段的数据时,内核会将其转到一个全零页面,不会发生缺页故障,也不会为其分配相应的物理内存。
运行时数据段和BSS段的整个区段通常称为数据区。某些资料中“数据段”指代数据段 + BSS段 + 堆。
.heap段用于存放进程运行时动态分配的内存段,可动态扩张或缩减。堆中内容是匿名的,不能按名字直接访问,只能通过指针间接访问。当进程调用malloc(C)/new(C++)等函数分配内存时,新分配的内存动态添加到堆上(扩张);当调用free(C)/delete(C++)等函数释放内存时,被释放的内存从堆中剔除(缩减) 。
.stack又称堆栈,由编译器自动分配释放,行为类似数据结构中的栈(先进后出)
主要有三个用途:
(1)为函数内部声明的非静态局部变量提供存储空间
(2)记录函数调用过程中相关的维护性信息
(3)临时存储区,用于暂存长算式表达式部分计算结果或alloca()函数分配的栈内内存
Linux中可以用ulimit -s命令来查看和设置堆栈最大值,
函数堆栈调用开栈过程:
(1).压入实参 自右向左
(2).压下一行指令地址
(3).压调用方函数的栈底地址
(4).跳转到被调用方函数的栈帧
(5).开辟被调用方函数运行需要的栈空间
调用约定
_cdecl c标准调用约定
_stdcall windows下标准调用约定
_fastcall 快速调用约定
_thiscall 类成员方法调用约定
各约定不同点:
1.函数的符号生成
2.实参的入栈顺序
3.形参的开辟和清理
_cdecl 调用方 调用方
_stdcall 调用方 被调用方
_fastcall 调用方 被调用方