进程中虚拟地址空间区域的划分

代码在编译连接完成后,都会产生一个放在磁盘上的可执行文件.exe,当我们运行exe文件时会把程序从磁盘上加载到内存当中(这里说的内存不是物理内存,而是虚拟内存)。那么进程中的虚拟地址空间又是怎么划分的呢?

以x86体系下的32位linux环境下来看,linux系统会给当前进程分配一个2^32大小的一块空间,也就是4G大小的空间,当然如果是在64位下地址空间划分又是不同的。这里4G当中3G被分为用户空间,1G被分为内核空间,它的详细分布如下:
x86体系下32位Linux环境进程的虚拟地址空间分布
其中0x00000000——0x08048000是不可访问的预留空间
.text .rodata是存放指令的,为只读形式
.data存放已初始化且初始化不为0的数据
.bss存放未初始化或初始化为0的数据
.heap 堆 堆进行分配时是从低地址到高地址的
stack 栈 从下往上进行增长
ZONE_DMA 用于DMA操作,约16兆大小
ZONE_NORMAL 内核空间的PCD块,进程控制块,内核空间的线程以及内核函数运行时所依赖的栈空间等都在这部分存放,约800来兆大小
ZONE_HIGHMEM 高端内存,映射高地址的物理内存时做地址映射用的

以上便是x86体系下32位Linux环境进程的虚拟地址空间分布,单纯的看可能没那么容易深刻地理解,下面我们举一个例子来更直观地理解分布情况。

#include <iostream>
using namespace std;

int data1 = 1;
int data2 = 0;
int data3;

static int data4 = 2;
static int data5 = 0;
static int data6;

int main()
{
	int a = 12;
	int b = 0;
	int c;

	static int e = 34;
	static int f = 0;
	static int g;

	cout<<c<<g<<endl;

	return 0;
}

其中全局变量data1-6不管是普通的还是静态的,它们统称为数据,它们编译以后在符号表中都会产生符号。
data1和data4因为初始化且不为0,故存放在.data段中,data2、3、5、6因为未初始化或初始化为0,存放在.bss段中。

a,b,c这三个普通局部变量不产生符号,他们对应生成的是指令。如a在x86体系下生成mov指令:dword ptr[a],0Ch 。这三个局部变量最终生成3个mov指令,存放在.text段中。

e,f,g这三个静态的局部变量也放在数据段,当程序启动的时候他们不会初始化,当第一次运行到他们时才进行初始化,e初始化为34,故存放在.data段,f和g因为初始化为0和未初始化所以存放在.bss段。

最后打印局部变量c的值不为0但是会报错,因为它是栈上的无效值;而打印g的值会打印出0,是因为内存运行完后会把内存的.bss这部分的内容全部清零,所以g打印出来的是0。

回头看整个代码,其中int main()、定义普通局部变量a,b,c、cout<<c<<g<<endl;、return 0;和括起主函数的中括号产生的都是指令,都在.text段上存放。而定义全局变量data1-6,定义静态局部变量e,f,g都是数据,都在.data段或.bss段上存放。

这时可能会有疑问,局部变量a,b,c不是在栈上存放吗?为什么产生的是指令呢?这其实是概念的问题,a,b,c经过编译后产生的是3个指令,这3个指令存放在.text段上。可是当这个函数运行的时候,系统会在当前的栈上给这个函数开辟一个栈帧,如dword ptr[a],0Ch这个指令运行的时候,会将12存放在a这4字节内存里面,所以这个指令运行的时候会在栈上划分出来4字节的一块空间来存放12,并不是a在栈上。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值