LINUX进程地址空间

目录

1.虚拟地址

2.页表 

3.总结

4.拓展知识细节


引言:想必大家在学习c语言的时候都看到过,这样的一张图片,再c语言的学习时候呢,我们都知道局部变量是存在栈区的动态开辟的内存是存在堆区的常量字符串是存在字符常量区的等等,但是这样图你是否是真的了解了呢,我们动态开辟的内存是不是真的就在内存中开辟一块的空间呢?

LINUX进程地址空间_第1张图片

1.虚拟地址

这段代码,我们用fork创建了一个子进程,父进程和子进程会同时执行printf

#include
#include

int main()
{
    pid_t pid = fork();
    printf("pid:%d path:%p\n",pid,&pid);
    return 0;
}

执行结果

我们神奇的发现,pid一个变量竟然有两个值而且这两货的地址还是相同的,由这个现象可以得出2个结论

(1)变量的内容不同,所以这两个pid绝对不是一个pid

  (2)   地址不同,这个地址绝对不是内存中真实的地址。

解释:(1)在linux下这种地址叫做虚拟地址

             (2)  c/c++中的地址一概是虚拟地址,真实的物理地址是由操作系统统一管理,用户看不到,这也是一种对操作系统的保护

2.页表 

简单理解:页表可以分为两块,左边存储着虚拟地址,右边存着物理地址,页表把虚拟的地址经过映射,映射到物理地址。

虚拟地址------>映射关系------>物理地址

3.总结

有了上面的知识储备,我们也就能解释,为什么一个变量有两个值,地址是相同的问题。

虽然这两变量的虚拟地址是相同的,但是别忘了,映射关系可以不同,修改一下映射关系,子进程pid地址就可以映射到物理地址的其他位置。

下图可以非常清楚的表示

LINUX进程地址空间_第2张图片

4.拓展知识细节

1.在地址空间,栈和堆的大小,其实是由个整形变量维护的,就像画了两条线,这两条线之间就是堆或者栈的大小。

2.当在虚拟地址空间动态开辟内存时,不会直接为其分配物理内存,使用时会引发缺页中断,这个时候操作系统介入,为其分配物理内存。

3.fork()创建子进程,首先会以父进程为模板,创建task_struct,然后指向父进程的地址空间,当子进程要对变量修改时会发生写时拷贝。

4.fork()之后代码子进程和父进程共享

5.虚拟地址到物理地址的转换,是cpu中一个叫MMU的寄存器做的

你可能感兴趣的:(linux,运维,服务器)