【c++】——进程虚拟地址空间


总所周知,任何的编程语言都会产生指令和数据。例如下面一段代码

#include<iostream>
#include<string.h>
using namespace std;

int gdata1 = 10;
int gdata2 = 0;
int gdata3;

static int gdata4 = 11;
static int gdata5 = 0;
static int gdata6;

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

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

	return 0;
}

这段代码经过编译产生**.exe的可执行文件是在磁盘上**的,通过cup将其加载到内存中。
但是注意!不可能直接加载到物理内存上。系统都会给当前进程开辟一个虚拟地址空间。接下来,我们来好好了解一下进程虚拟地址空间吧~

1、进程虚拟地址空间大小

X86 32位linux系统中,linux系统会给当前进程分配一个2^32大小的一块空间(4G

2、虚拟的含义

关于虚拟的含义,我们可以这样来解释。
它存在,你能看得见,他是物理的。
它存在,你看不见,他是透明的。
他不存在,你却看得见,他是虚拟的。
他不存在,你也看不见,他被删除了

3、空间分配情况

如下图所示:
在这里插入图片描述
总体上来说,进程虚拟地址空间分为用户空间和内核空间两个部分,从上到下地址减小。接下来,我们来介绍相关区域的具体含义。

(1)不可访问区
由字面意思我们就可以了解到,它是指的这段区域是我们不可访问的,如下面一段代码:

char* p = nullptr;
strlen(p);
char* src = nullptr;
strcpy(dest,src)

p指向了一个不可访问区,我们从0地址打算拷贝一个字符串,但是程序运行直接崩溃,因为0地址空间是不可访问的。

(2).text(代码段) .rdata(只读数据段)
实质上这两个段不是一个,是紧挨着的两个段,但是由于他们的属性相同,所以我们在此混为一谈。我们都知道指令在编译的时候放在.text中
我们有如下一个定义:

char *p = "hello world" 
*p = 'a';

他的含义是在函数里面,定义一个局部变量指针在栈上,指向了一个常量字符串"hello world"
但是由于p是放在.rdata段,**编译时没有问题但是运行不了,**因为只能读但是不能写。
所以一般的只能写成

const char *p = "hello world"

(3).data.bss数据段

**.data专门存放初始化了的,而且初始化值不为0的,.bss存放未初始化和初始化为0。**例如:

int gdata;
cout<<gdata<<end

以上代码我们会输出0,因为操作系统会把.bss里面的数据全部初始化为0

(4).heap
程序运行了过后调用new或者malloc才会分配堆内存(从低地址到高地址)

(5).stack
函数运行产生线程池,每一个线程独有的栈空间(从下往上)

(6)命令行参数和环境变量
命令行参数:程序运行会传入 比如Linux中的.\a.out 192.168.1.100 9090
环境变量,程序在搜索头文件搜索库文件默认的路径

4、具体空间指向

本篇文章开始的时候说给出的代码与进程虚拟地址空间对应如下:
在这里插入图片描述
(1)编译产物
main函数之外的都成为数据会生成符号,但是main函数里面的局部变量会生成指令,具体的操作如下:

int a = 20;
对应的指令是:mov dword ptr[a],0Ch

局部变量在编译的时候会生成指令在.test段,这条指令运行的时候系统会在当前进程的栈上开辟一个栈帧。开辟一个四字节的空间存放12这个整数

(2)对应区域
由上图的颜色我们可以一一对应。

(3)每一个进程的用户空间是私有的,但是内核空间是共享的
如下图所示,当我们有qq,酷狗和vs同时在线的时候,他们的进程虚拟地址空间如下:
在这里插入图片描述
每个进程的用户空间是相互隔离的,但是内核空间都是共享的。

发布了62 篇原创文章 · 获赞 7 · 访问量 2552

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104975151