1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<stdlib.h>
6
7 int g_val=100;
8
9 int main()
10 {
11 printf("father is running,pid:%d,ppid:%d\n",getpid(),getppid());
12
13 pid_t id=fork();
14 if(id==0)
15 {
16 while(1)
17 {
18 printf("I am child process,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
sleep(1);
19 }
20 }
21 else
22 {
23 while(1)
24 {
25 printf("I am father process,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
26 }
sleep(1);
27 }
28 return 0;
29 }
我们发现,输出出来的变量值和地址是一模一样的,很好理解,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改
现在对代码进行修改
改变子进程中的变量值再输出结果:
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!
OS必须负责将 虚拟地址 转化成 物理地址 。
地址空间的本质就是内核中的一个结构体对象,子进程会把父进程的很多内核数据结构全拷贝一份(浅拷贝),当子进程尝试对变量进行修改时,我在物理内存重新开辟一块空间,新的物理地址放到页表当中,重新构建映射
在虚拟内存系统中,每个进程都拥有一块连续的虚拟地址空间,这块空间由操作系统管理,对进程来说,它看起来像是独占的内存。虚拟地址不直接对应物理内存中的实际位置,而是通过一系列的映射过程转换成物理地址
页表是实现虚拟地址到物理地址映射的数据结构。操作系统将虚拟内存分割成固定大小的块,称为“页”(pages),物理内存也被分割成同样大小的“页帧”(page frames)。页表存储着虚拟页和相应物理页帧之间的映射信息。
上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址
写时拷贝(Copy-On-Write,简称 COW)是一种优化策略,用于进程管理和内存管理中,以减少数据复制的需要,节省资源并提高效率
在操作系统中,写时拷贝主要用于实现 fork()
系统调用时的内存效率优化。当一个进程调用 fork()
创建子进程时,操作系统原本需要复制整个进程的地址空间到子进程中。然而,通过使用写时拷贝技术,子进程最初会共享父进程的地址空间中的所有页,而不是物理上复制它们。
fork()
后,父进程和子进程会共享同一物理内存页,每个页表项被标记为只读。地址空间划分
在操作系统的地址空间管理中,地址空间被划分为几个区域,以组织不同类型的数据和代码。这些区域的划分是为了提高内存的管理效率、安全性和程序的运行性能。以下是典型的地址空间中的主要区域:
malloc
, new
等函数),这些内存块将从堆上分配。堆的大小不是静态的,它会根据程序的需求动态增长和缩减。堆通常从低地址向高地址增长。
这些区域的划分允许操作系统更有效地管理不同类型的数据和代码,确保它们正确、高效地运行,并保护程序数据不被非法访问或破坏。通过精确控制这些区域的访问权限(如只读、执行、读写),操作系统提高了整个系统的稳定性和安全性。
地址空间本质是内核的一个struct结构体!内部很多的属性都是表示start , end的范围
理解地址空间的概念涉及到对现代操作系统中如何处理和隔离不同程序和进程的内存资源的基本认识。地址空间基本上是一个抽象的概念,用来表示为一个特定的进程分配的所有可用内存,包括代码、数据、堆和栈等。这里是一些核心点来帮助更好地理解地址空间:
1. 虚拟内存与物理内存的区别
2. 地址空间的作用
3. 管理和优化
fork()
系统调用中。父进程和子进程最初共享相同的物理内存页,仅当其中一个进程尝试修改页时,操作系统才会为该进程创建这个页的副本。4. 实际应用
在程序编写时,开发者不需要处理地址空间的具体细节,这些都由操作系统和编译器自动处理。程序员主要关注的是如何高效地使用内存,例如通过优化数据结构和算法来减少内存的需求和提高缓存的利用率。
地址空间是每个进程独立享有的虚拟内存布局,它包括了程序执行所需的所有类型的内存区域。通过操作系统的内存管理机制,如页表和内存管理单元(MMU),虚拟地址被映射到物理地址,从而实现虚拟内存的抽象。这不仅保证了操作系统的灵活性和应用程序的安全性,还提高了内存使用的效率和程序的可扩展性。
实际的物理内存中,代码区数据区,堆区,栈区,共享区,命令行参数和环境变量是无序的,那么地址空间的第一个作用,就是将无序变成有序,让进程以统一的视角看待物理内存及自己运行的各个区域
虚拟内存技术允许每个进程使用的内存超过实际的物理内存容量。地址空间的使用使得操作系统可以有效地管理内存,将不活跃的页交换到磁盘,将频繁使用的页保持在快速的物理内存中。这种灵活的内存管理策略使得更多的应用能够同时运行,而不受物理内存大小的直接限制
地址空间为每个进程提供了一个独立的内存视图,确保一个进程无法直接读取或修改另一个进程的内存。这种隔离保护了系统的稳定性,防止了错误或恶意的进程干扰其他进程。如果没有地址空间的隔离,一个进程的崩溃可能导致整个系统的崩溃
所有非法访问都不能通过虚拟地址空间访问到物理内存,对物理内存起到保护作用
页表当中每一个条目,有标记位等更多细节
写时拷贝工作机制:
程序内部使用的地址都是基于虚拟地址空间,页表负责将这些地址实时映射到实际的物理内存地址,为程序的正确执行提供支撑
前面提到的nice值范围在[-20,19]
在 Linux 2.6 内核中,进程调度得到了很大的改进,以提高系统的效率、响应性和可扩展性。Linux 2.6 使用了一种称为 Ø(1)调度器 的调度算法,这种算法通过使用多个调度队列来达到高效调度。以下是对这些调度队列及相关机制的详细解释:
Ø(1)调度器概述
数组下标就是优先级!
从该结构中,选择一个最合适的进程,过程是怎么的呢?
一个只出不进,一个只进不出