您的位置:首页 > 运维架构 > Linux

linux进程系列(3)父子进程变量虚拟内存地址相同但变量值不同的问题

2016-11-13 17:40 351 查看
    首先,我们来看一个实例:

process_fork3.c

/*

 * process_fork3.c

 *

 *  Created on: 2016-11-13

 *      Author: river

 */

/*

 * process_fork.c

 *

 *  Created on: 2016-11-11

 *      Author: river

 */

#include <unistd.h>

#include <string.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

//全局变量

int g_v = 30;

int main()

{

    int a_v = 30;//局部变量

    static int s_v = 30;//静态变量

    pid_t pid;

    pid = fork();//创建子进程

    //在fork之后会运行2个进程(父进程、子进程)

    if(pid < 0)

    {

        perror("fork error");

    }

    else if(pid > 0)

    {//父进程(在父进程中fork返回的是子进程的pid)

     //父进程执行的代码...

        g_v = 40;

        a_v = 40;

        s_v = 40;

        printf("I am parent process pid is %d\n", getpid());

        printf("g_v: %p, a_v: %p, s_v: %p\n\n\n", &g_v, &a_v, &s_v);

    }

    else

    {//子进程(在子进程中fork返回的是0)

     //子进程执行的代码...

        printf("kkkpid: %d, g_v:%d, a_v:%d, s_v:%d\n", getpid(), g_v, a_v, s_v);//父子进程都执行

        g_v = 50;

        a_v = 50;

        s_v = 50;

        printf("I am child process pid is %d\n", getpid());

        printf("g_v: %p, a_v: %p, s_v: %p\n\n\n", &g_v, &a_v, &s_v);

    }

   

   
printf("pid: %d, g_v:%d, a_v:%d, s_v:%d\n\n\n", getpid(), g_v, a_v, s_v);//父子进程都执行

    sleep(1);//睡眠1s使得父子进程可以交替运行

    exit(0);

}

    上面的例子,我们定义3个变量,分别是全局变量、局部变量、静态变量,并都赋予初始值30,在父进程中都修改为40,并打印三个变量的地址,在子进程中都修改为50,并打印三个变量的地址,最后父子进程分别打印三个变量的值。

程序运行输出结果为:

I am parent process pid is 21268

g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038

pid: 21273, g_v:30, a_v:30, s_v:30
pid: 21268, g_v:40, a_v:40, s_v:40

I am child process pid is 21273
g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038

pid: 21273, g_v:50, a_v:50, s_v:50

     从上面的输出结果我们可以看到父进程的ID是21268,子进程的ID是21273,我们用绿色标示了父进程的输出信息,蓝色标示了子进程的输出信息。

      对于pid: 21273, g_v:30, a_v:30, s_v:30这一句的解释是 在程序运行开始我们将三个变量都初始化为30,因此子进程在没有对三个变量进行修改之前,我们打印的三个变量的值是从父进程中继承而来的数值(注意父进程是在fork之后对三个变量修改为40的,所以父进程拷贝到子进程中的三个变量的值仍然是父进程初始化为30的值),这也就验证了上一篇文章中提到的子进程会遗留父进程中的数据。

      我们会看到这样一个现象:

      I am parent process pid is 21268 

      g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038

          I am child process pid is 21273
      g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038

          父进程变量的地址与子进程变量的地址是一样的,也就是说不同的进程的变量却有相同的虚拟地址(注:程序中变量的地址都是虚拟地址,而非物理地址)。原因是内核会为每个进程分配4G的虚拟地址空间,这4G的虚拟地址空间地址分布都是一样的,由于子进程虚拟地址空间的数据都是从父进程中拷贝而来的,都是一样的,因此相同的数据在4G的虚拟地址空间中的分布也是一样的。那为什么相同的虚拟地址(变量地址)最终会得到不同的变量值呢?原因是虽然虚拟地址分布是一样的,但是由于相同的虚拟地址映射到不同的物理地址,所以我们才会得到不同的变量值。

     下面的示图描了这一点:

                    


    从上图可以看到,虽然父进程与子进程中三个变量虚拟地址是一样的,但是映射到不同的物理地址就得到了不同的数值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: