进程地址空间——笔记

进程地址空间(每个进程都有)

#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<unistd.h>

int g_val = 100;
int main()
{
	pid_t id = fork();
	if(!id)
	{
		int count = 0;
		while(1)
		{
 			printf("child, pid:%d   ppid:%d  g_val:%d  &g_val:%p\n", getpid(), getppid(), g_val, &g_val);
		 	sleep(1);
			count++;
			if(count == 5)                                                                                                                                                                   
 			{
		         g_val = 200;
			 	printf("chage sccess\n");
			}
        }
	}
	else
	{
		while(1)
		{
			printf("parent, pud:%d   ppid:%d  g_val:%d  &g_val:%p\n", getpid(), getppid(), g_val, &g_val);
        	sleep(1);
        }
	}
	return 0;
}


上面代码运行后如下所示:
在这里插入图片描述
上面父、子进程同一个变量,相同的地址却有两个值,说明该地址不是物理地址。

在这里插入图片描述
字符常量区也在正文代码区

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_unval;
int g_val = 100;

int main(int argc, char *argv[], char *env[])
{
	  printf("code addr: %p\n", main);
	  printf("init global addr: %p\n", &g_val);
	  printf("uninit global addr: %p\n", &g_unval);

	  static int test = 10;
	  char* heap = (char*)malloc(10);
	  char* heap1 = (char*)malloc(10);
	  char* heap2 = (char*)malloc(10);
	  char* heap3 = (char*)malloc(10);
	  printf("static stack addr: %p\n", &test);
	  printf("heap addr: %p\n", heap);
	  printf("heap1 addr: %p\n", heap1);
	  printf("heap2 addr: %p\n", heap2);
	  printf("heap3 addr: %p\n", heap3);
	  printf("stack addr: %p\n", &heap);
	  printf("stack1 addr: %p\n", &heap1);
	  printf("stack2 addr: %p\n", &heap2);
	  printf("stack3 addr: %p\n", &heap3);

	  int i = 0;
	  for(i = 0; i < argc; i++)
	  {
	  	  printf("argv[%d]: %p\n", i, argv[i]);
	  }
	  for(i = 0; env[i]; i++)
	  {
	  	  printf("env[%d]: %p\n", i, env[i]);
	  }
	  return 0;
} 

什么是地址空间

以画饼为例
老板给员工画饼,说给予5%的股份
老板 —— 操作系统
员工们 —— 进程
饼 —— 地址空间
股份 —— 物理内存
同时,画的饼应该和相应的人对应起来,因此需要OS进行管理
所以,地址空间本质是种数据结构,将来要个对应的进程关联起来

地址空间是怎么设计的

是一种专门为进程设计的内核数据结构,里面有各个区域的划分,结合页表控制物理内存的内容和区域

页表有对应关系和读写权限等
在这里插入图片描述
以压岁钱为例,去小卖部买东西。
在这里插入图片描述
如:想买个3090卡,必定会被拒绝;买点吃的会允许
在页表中无法正确映射就直接拒绝访问

只要保证,每个进程的页表,映射的是物理内存的不同区域,就可以保证其独立性
空间配置器配置的就是虚拟内存空间
在这里插入图片描述
进程在编入内存之前就已经有了虚拟地址

语言中的地址都是虚拟地址(线性地址),不是物理地址 ,同时需要编译器的配合

CPU始终访问的是虚拟地址

注:递归的栈大小不大,只有几MB

地址空间页表 是OS创建和维护的
使用地址空间和页表一定是在OS的监管下进行访问的

为啥要有虚拟地址?

1、 凡是非法的访问或映射,OS都会识别并终止该进程(如是否有读写权限),有效保护了物理内存,也保护物理内存中合法数据的安全和内核相关的有效数据(压岁钱的例子)
2、 因地址空间和页表的存在,在物理内存中,对未来的数据可以进行任意位置的加载。物理内存的分配 和 进程管理模块(PCB)就可以做到没关系了(解耦合)
在这里插入图片描述
例如:进行malloc、new操作,当没进行使用访问时,物理内存甚至半个字节都不给,此时仅仅在地址空间中申请。当真正使用访问时(缺页中断)才会给。
以上的方式称为延时分配,提高整机效率
3、 在物理内存上理论上可以在任意位置进行加载,可以认为物理内存中的数据和代码是乱序的。
但是,由于页表的存在,在进程视角的内存分布,可以看作是有序的。
由2可得目前要访问的数据和代码,不一定在物理内存中;同样,可以让不同的进程映射到不同的物理内存。
由上可得,每个进程都认为自己有4GB(假设)的空间,并且各个区域是有序的。每个进程也不知道其他进程的存在。

进程: 对应的数据和代码() + 内核数据结构
下面红方框中的合起来叫进程
在这里插入图片描述

什么是挂起(重新看进程状态)

加载本质就是创建进程,那么是不是必须非得立马把所有的程序的代码和数据加载到内存中,并创建内核数据结构建立映射关系?
实际是不会的
在最极端的情况下,甚至只有内核结构被创建出来了!
那么可以称这个进程为新建状态!!
理论上,可以实现进程分批加载/换入。——>也可以分批换出——>甚至短时间内不被执行,阻塞——>进程的代码和数据被换出,叫做挂起

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值