当前位置:   article > 正文

linux进程内存映象解析_linux进程影像

linux进程影像

一、程序如何转化为进程

程序转化为进程一般有两个步骤:
1、内核会将程序从磁盘读入内存,为程序分配内存空间
2、内核会为进程保存PID以及相应的状态信息(保存在task_struct中),将进程放在运行队列中等待执行。
程序转变为进程以后就可以被操作系统调度程序执行了。

二、内存映象

内存映象指的是内核如何在内存中存放可执行程序。
在程序转化为进程的过程中,操作系统可直接将可执行程序复制到内存中,其分布状况如下:
这里写图片描述
(1)栈的地址是由高地址向低地址生长的(这也就解释了为什么我们定义数组的时候要给定数组大小)
(2)堆的地址是有低地址向高地址生长的

三、虚拟地址与物理地址

结合子进程与父进程,我们可以将上图画的更详细:
这里写图片描述
1、地址空间(在操作系统中是现实存在的,由地址空间结构体支持):指的是虚拟地址上的一个地址范围,按需要来获取。举个形象点的例子来说明:你活动的范围是西安,但是最终你真正落脚的只是交通大学419宿舍的2号床铺。也就是说整个西安你都可以访问,但最终属于你的只是你现在坐的那块固定大小的地方。
2、虚拟地址:每个进程有运行在一个属于自己的地址空间里面,这个地址空间就是虚拟地址(我们平时见到的也都是虚拟地址,但最终还是要映射到物理地址上去)。
3、MMU:内存管理单元(硬件),结合页表可以完成映射。

上面我们说虚拟地址是每个进程特有的空间,并且我们见到的和用的都是虚拟地址,现在我们通过一段来验证一下:

int g_val=100;
int main()
{
    pid_t id=fork();
    if(id<0)//fork error
    {
        printf("fork error\n");
        return 1;
    }
    else if(id==0)//child 
    {
        g_val=1000;
        printf("child ,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
    }
    else
    {
        sleep(3);
        printf("father ,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
    }
    return 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出:
这里写图片描述
在子进程中将全局变量g_val的值改为1000;
在父进程中显示值为100,子进程中值为1000,并且两者的地址是相同的。

结合上面的图我们来解释一下这个现象:我们说子进程和父进程共享代码,但是数据并不是共享的,也就是说,他们的虚拟地址是一样的,但是物理地址就肯定不一样了。父进程根据自己的页表和MMU映射到一个物理地址,子进程也映射到一个地址。子进程改一个值并不影响父进程的值,所以就出现了上面变量地址相同而值不同的情况。

PS:父子进程数据私有化的实现:并不是立刻实现,而是当有进程对某个区域的数据进行写入的时候,实现对该进程空间的数据的私有化,私有化的实现技术是写时拷贝。这样做的目的是为了节省消耗,提高效率。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/769972
推荐阅读
相关标签
  

闽ICP备14008679号