printf()缓冲区问题缓冲区输出条件1.缓冲区满了 2.缓冲区被强制刷新了 3.进程结束时基于exit退出exit() stdlib.h C标准库函数_exit() unistd.h Unix系统调用exit()终止逻辑先执行用户态的资源清理操作再调用内核实现终止逻辑1. 刷新并关闭标准I/O流强制刷新缓冲区的数据加了\n时缓冲区内容会被输出到终端或文件中2. 清理私有资源释放进程占用的用户态内存堆内存全局变量内存3. 调用_exit()触发内核回收_exit()终止逻辑他是系统调用会跳过用户态的所有操作直接通知内核终止进程普通的单进程程序优先使用exit()多进程例如父子进程子进程优先使用_exit()主函数的参数argc:主函数参数个数argv[]:主函数的参数内容envp[]:环境变量的内容进程是动态的执行过程占用cpu和内存资源程序是静态的代码和数据是待执行的指令集合不占用cpu内存资源fork()复制进程fork() : unistd.hLinux专属头文件 函数原型 pid_t fork(void) 不需要参数返回值pid_t是进程ID的整形类型 有三种不同的返回值1. 在父进程中返回子进程的pid用于父进程识别和管理子进程2.子进程中返回0用于子进程确认自身身份3. 出错时返回-1比如内存不足系统进程数达到上限设置error表示错误原因指令perror可查看出错原因僵尸进程子进程先于父进程结束父进程由于没有获得子进程的退出码子进程变成僵死进程【进程结束是先将子进程原本的内容清空了然后他会遗留一个pid。如果发现子进程挂掉了父进程就会通知内核内核来干掉子进程的pid】孤儿进程:父进程先于子进程结束子进程变成孤儿进程但是系统会给子进程重新分配新的父进程因为目的是确保子进程不会称为僵死进程导致内存占用运行态就绪态阻塞态Wait()阻塞当前进程父进程回收子进程资源避免僵死进程同时获取将阻塞后的退出状态首先在Linux的进程复制过程中会采用一种“写实拷贝”的方式写实拷贝:延迟实现拷贝操作仅在必要时执行是一种高效的内存共享与复制的策略为什么需要?如果不采用该方法想要复制一块内存(例如fork)会直接执行全量拷贝将父进程的代码段数据段堆栈完整的复制到子进程的内存地址空间中会造成CPU和内存带宽的严重浪费当实际内存页发生实际修改时才会执行拷贝任务未修改的页始终共享避免无效拷贝。我们现在所能看到的计算机上去所有的地址全部都是逻辑地址物理地址在内存条上面逻辑地址和物理地址早期使用物理地址的缺点1.内存冲突: 多个程序同时运行时如果都访问同一物理地址会导致数据覆盖2.内存浪费: 程序需要多个连续的内存块如果内存中有小块的空闲内存即使总空间足够也会造成浪费3.安全性低因为程序可以直接访问物理地址会导致恶意程序修改内存数值内存访问流程:1.假设执行inta0x1234(分配一块逻辑地址 0x56789999) 32位系统2.CPU会将逻辑地址拆分为两部分 v 0x56789 页内偏移0x9993.由MMU使用 0x56789 变量 查进程页表 找到值为 0xabcde4.拼接物理地址:0xabcde 9995.由内存控制器访问0xabcde999将0x1234写入该地址完成变量赋值逻辑地址给程序看 物理地址给硬件看MMU和页表是两者的翻译官使用这一机制实现了现代操作系统多进程内存保护虚拟内存的基础编译完成时逻辑地址确定下来首先在linux的进程复制过程中会采用一种“写实拷贝”的方式写实拷贝——延迟实现拷贝操作仅在必要时执行是一种高效的内存共享与复制的策略为什么需要如果不采用该方法想要复制一块内存例如fork会直接执行全量拷贝将父进程的代码段数据段堆栈完整的复制到子进程的内存地址空间中会浪费大部分空间——造成CPU和内存带宽的严重浪费当实际内存页发生实际修改时才会执行拷贝任务未修改的页始终共享避免无效拷贝逻辑地址本质虚拟空间的地址软件层面的地址作用范围只在当前进程有效使用者开发者空间范围由操作系统分配与物理内存大小无关。32位系统有4个G稳定性由操作系统的虚拟内存机制决定与物理硬件无关物理地址本质物理内存硬件地址真实存在作用范围全系统唯一使用者内存控制器空间范围物理内存容量有关稳定性是硬件固定的仅硬件配置发生变化维度 逻辑地址虚拟地址 物理地址本质 虚拟内存空间的地址软件层面地址 物理内存芯片的硬件地址真实存在作用范围 仅当前进程内有效进程间独立 全系统唯一所有硬件 / 进程共享使用者 程序员 / 编译器 / 操作系统软件层 内存控制器 / 硬件硬件层空间范围 由系统架构决定与物理内存无关 与实际物理内存容量完全一致典型范围 32 位系统固定 4GB64 位系统更大 如 8GB/16GB/32GB实际装机内存稳定性 与硬件无关进程重启可变化 硬件固定仅硬件配置变化改变早期使用物理地址的缺点1. 内存冲突多个程序同时运行时如果都访问统一物理地址会导致数据覆盖2. 内存浪费程序需要多个连续的内存块如果内存中有小块的空闲内存即使总空间足够也会造成浪费3. 安全性低因为程序可以直接访问物理地址会导致恶意程序修改内存数值内存访问流程1. 假设执行 int a 0x1234(分配一块逻辑地址 0x56789999)32位系统2. CPU会将逻辑地址拆分为两部分 v0x56789() 页内偏移0x9993. 由MMU内存控制器使用0x56789变量 查进程页表 找到值为0xabcde4. 拼接物理地址拼接成0xabcde 9995. 由内存控制器访问0xabcde999将0x1234写入该地址完成变量赋值逻辑地址——给程序看物理地址——给硬件看MMU和页表是两者的翻译官 使用这一机制实现了现代操作系统 多进程内存保护虚拟内存的基础。编译完成时逻辑地址确定下来
exit()终止逻辑 fork()复制进程
printf()缓冲区问题缓冲区输出条件1.缓冲区满了 2.缓冲区被强制刷新了 3.进程结束时基于exit退出exit() stdlib.h C标准库函数_exit() unistd.h Unix系统调用exit()终止逻辑先执行用户态的资源清理操作再调用内核实现终止逻辑1. 刷新并关闭标准I/O流强制刷新缓冲区的数据加了\n时缓冲区内容会被输出到终端或文件中2. 清理私有资源释放进程占用的用户态内存堆内存全局变量内存3. 调用_exit()触发内核回收_exit()终止逻辑他是系统调用会跳过用户态的所有操作直接通知内核终止进程普通的单进程程序优先使用exit()多进程例如父子进程子进程优先使用_exit()主函数的参数argc:主函数参数个数argv[]:主函数的参数内容envp[]:环境变量的内容进程是动态的执行过程占用cpu和内存资源程序是静态的代码和数据是待执行的指令集合不占用cpu内存资源fork()复制进程fork() : unistd.hLinux专属头文件 函数原型 pid_t fork(void) 不需要参数返回值pid_t是进程ID的整形类型 有三种不同的返回值1. 在父进程中返回子进程的pid用于父进程识别和管理子进程2.子进程中返回0用于子进程确认自身身份3. 出错时返回-1比如内存不足系统进程数达到上限设置error表示错误原因指令perror可查看出错原因僵尸进程子进程先于父进程结束父进程由于没有获得子进程的退出码子进程变成僵死进程【进程结束是先将子进程原本的内容清空了然后他会遗留一个pid。如果发现子进程挂掉了父进程就会通知内核内核来干掉子进程的pid】孤儿进程:父进程先于子进程结束子进程变成孤儿进程但是系统会给子进程重新分配新的父进程因为目的是确保子进程不会称为僵死进程导致内存占用运行态就绪态阻塞态Wait()阻塞当前进程父进程回收子进程资源避免僵死进程同时获取将阻塞后的退出状态首先在Linux的进程复制过程中会采用一种“写实拷贝”的方式写实拷贝:延迟实现拷贝操作仅在必要时执行是一种高效的内存共享与复制的策略为什么需要?如果不采用该方法想要复制一块内存(例如fork)会直接执行全量拷贝将父进程的代码段数据段堆栈完整的复制到子进程的内存地址空间中会造成CPU和内存带宽的严重浪费当实际内存页发生实际修改时才会执行拷贝任务未修改的页始终共享避免无效拷贝。我们现在所能看到的计算机上去所有的地址全部都是逻辑地址物理地址在内存条上面逻辑地址和物理地址早期使用物理地址的缺点1.内存冲突: 多个程序同时运行时如果都访问同一物理地址会导致数据覆盖2.内存浪费: 程序需要多个连续的内存块如果内存中有小块的空闲内存即使总空间足够也会造成浪费3.安全性低因为程序可以直接访问物理地址会导致恶意程序修改内存数值内存访问流程:1.假设执行inta0x1234(分配一块逻辑地址 0x56789999) 32位系统2.CPU会将逻辑地址拆分为两部分 v 0x56789 页内偏移0x9993.由MMU使用 0x56789 变量 查进程页表 找到值为 0xabcde4.拼接物理地址:0xabcde 9995.由内存控制器访问0xabcde999将0x1234写入该地址完成变量赋值逻辑地址给程序看 物理地址给硬件看MMU和页表是两者的翻译官使用这一机制实现了现代操作系统多进程内存保护虚拟内存的基础编译完成时逻辑地址确定下来首先在linux的进程复制过程中会采用一种“写实拷贝”的方式写实拷贝——延迟实现拷贝操作仅在必要时执行是一种高效的内存共享与复制的策略为什么需要如果不采用该方法想要复制一块内存例如fork会直接执行全量拷贝将父进程的代码段数据段堆栈完整的复制到子进程的内存地址空间中会浪费大部分空间——造成CPU和内存带宽的严重浪费当实际内存页发生实际修改时才会执行拷贝任务未修改的页始终共享避免无效拷贝逻辑地址本质虚拟空间的地址软件层面的地址作用范围只在当前进程有效使用者开发者空间范围由操作系统分配与物理内存大小无关。32位系统有4个G稳定性由操作系统的虚拟内存机制决定与物理硬件无关物理地址本质物理内存硬件地址真实存在作用范围全系统唯一使用者内存控制器空间范围物理内存容量有关稳定性是硬件固定的仅硬件配置发生变化维度 逻辑地址虚拟地址 物理地址本质 虚拟内存空间的地址软件层面地址 物理内存芯片的硬件地址真实存在作用范围 仅当前进程内有效进程间独立 全系统唯一所有硬件 / 进程共享使用者 程序员 / 编译器 / 操作系统软件层 内存控制器 / 硬件硬件层空间范围 由系统架构决定与物理内存无关 与实际物理内存容量完全一致典型范围 32 位系统固定 4GB64 位系统更大 如 8GB/16GB/32GB实际装机内存稳定性 与硬件无关进程重启可变化 硬件固定仅硬件配置变化改变早期使用物理地址的缺点1. 内存冲突多个程序同时运行时如果都访问统一物理地址会导致数据覆盖2. 内存浪费程序需要多个连续的内存块如果内存中有小块的空闲内存即使总空间足够也会造成浪费3. 安全性低因为程序可以直接访问物理地址会导致恶意程序修改内存数值内存访问流程1. 假设执行 int a 0x1234(分配一块逻辑地址 0x56789999)32位系统2. CPU会将逻辑地址拆分为两部分 v0x56789() 页内偏移0x9993. 由MMU内存控制器使用0x56789变量 查进程页表 找到值为0xabcde4. 拼接物理地址拼接成0xabcde 9995. 由内存控制器访问0xabcde999将0x1234写入该地址完成变量赋值逻辑地址——给程序看物理地址——给硬件看MMU和页表是两者的翻译官 使用这一机制实现了现代操作系统 多进程内存保护虚拟内存的基础。编译完成时逻辑地址确定下来