Linux--程序地址空间

Posted L_add

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux--程序地址空间相关的知识,希望对你有一定的参考价值。

程序地址空间


	#include <stdio.h>
    2 #include <malloc.h>
    3 #include <unistd.h>
    4 #include <stdlib.h>
    5 int g_val = 100;
    6 int g_unval;
    7 int main(int argc,char *argv[],char *envp[])
    8 {
    9   printf("code addr:%p\\n",main);
W> 10   char* str = "hello world";
   11   printf("read only addr:%p\\n",str);
   12   printf("init addr:%p\\n",&g_val);
   13   printf("unint addr:%p\\n",&g_unval);
E> 14   int *p = malloc(10);
   15   printf("heap addr:%p\\n",p);
   16 
   17   printf("stack addr:%p\\n",&str);
   18   printf("stack addr:%p\\n",&p);
   19   int i;
   20   for( i = 0;i < argc;i++)
   21   {
   22     printf("argc addr:%p\\n",argv[i]);//ls -a -l
   23   }
   24   while(envp[i])
   25   {
   26     printf("envp addr:%p\\n",envp[i++]);                                                                                                                   
   27   }
   28 }

#include <stdio.h>
    2 #include <malloc.h>
    3 #include <unistd.h>
    4 #include <stdlib.h>
    5 int g_val = 100;
    6 int g_unval;
W>  7 int main(int argc,char *argv[],char *envp[])
    8 {
    9   pid_t id = fork();
   10   if(id == 0)
   11   {
   12     //child
   13     printf("child:pid :%d,ppid :%d,g_val :%d,&g_val :%p\\n",getpid(),getppid(),g_val,&g_val);
   14   }
   15   else{
   16     //father
   17     printf("father:pid :%d,ppid :%d,g_val :%d,&g_val :%p\\n",getpid(),getppid(),g_val,&g_val);
   18   }
   19   sleep(1);
   }                     


把g_val 改为200

#include <stdio.h>
    2 #include <malloc.h>
    3 #include <unistd.h>
    4 #include <stdlib.h>
    5 int g_val = 100;
    6 int g_unval;
W>  7 int main(int argc,char *argv[],char *envp[])
    8 {
    9   pid_t id = fork();
   10   if(id == 0)
   11   {
   12     //child
   13     g_val = 200;                                                                                                                                          
   14     printf("child:pid :%d,ppid :%d,g_val :%d,&g_val :%p\\n",getpid(),getppid(),g_val,&g_val);
   15   }
   16   else{
   17     //father
   18     printf("father:pid :%d,ppid :%d,g_val :%d,&g_val :%p\\n",getpid(),getppid(),g_val,&g_val);
   19   }
   20   sleep(1);
   21 }

父子进程,输出地址是一致的,但是内容不一样
结论

  • 变量内容不一样,所以父子进程输出的变量绝对不是一个变量
  • 地址值是一样的,说明该地址不是物理地址
  • LINUX下,这种地址叫做虚拟地址
  • C/C++语言所看到的地址,全都是虚拟地址。物理地址用户一概看不到,由OS统一管理
    OS负责将虚拟地址转化为物理地址

    所以说程序地址空间是不标准的,准确应该是进程地址空间

进程地址空间

分页&虚拟地址空间


写入(改变)时父子进程在数据层面发生了分离
子进程写入,不影响父进程,因为进程独立性
同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址



进程调度队列

一个CPU具有一个runqueue

  • 如果有多个CPU就要考虑进程个数的负载均衡问题

优先级

  • 普通优先级100~139(与nice取值相对应)
  • 实时优先级0~99

活动队列

  • 时间片还没有结束的所有进程都按照优先级放在该队列
  • nr_active:总共有多少个运行状态的进程
  • queue[140]:一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以数组的下标就是优先级
  • 从该结构中,选出一个最适合的进程

1、从0下标开始遍历queue[140]
2、找到第一个非空队列,该队列必定为优先级最高的对列
3、拿到选中队列的第一个进程,开始运行,调度完成
4、遍历数组queue[140]时间复杂度是常数,但是太低效了

  • bitmap[5]一共140个优先级,一共140个进程队列,为了提高查找非空间队列的效率,可以用5*32个比特位表示队列是否为空,这样可以提高查找效率

过期队列

  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间片耗尽的进程
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程时间片重新计算

active指针和expried指针

  • active指针永远指向活动队列
  • expried指针永远指向过期对列
  • 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的
  • 在合适的时候,交换active指针和expried指针的内容,就相当于有了一批新的活跃进程

总结

  • 在系统中查找一个最合适调度的进程时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法

以上是关于Linux--程序地址空间的主要内容,如果未能解决你的问题,请参考以下文章

Linux进程虚拟地址空间

Linux内核空间-理解高端内存

[OS-Linux]详解Linux的进程2(进程的优先级,环境变量,程序地址空间,进程地址空间,进程调度队列)

[OS-Linux]详解Linux的进程2(进程的优先级,环境变量,程序地址空间,进程地址空间,进程调度队列)

多线程编程

Linux篇第七篇——进程地址空间(程序地址空间+虚拟地址空间)