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--程序地址空间的主要内容,如果未能解决你的问题,请参考以下文章
[OS-Linux]详解Linux的进程2(进程的优先级,环境变量,程序地址空间,进程地址空间,进程调度队列)