河南网站建设网络公司,wordpress neoease,全国最大型网站建设,wordpress网站编辑文章目录 1.进程地址空间的理解2.将虚拟地址转换为物理地址3.进程地址空间的设计4.进程地址空间的好处 1.进程地址空间的理解
在 前文 分享的fork创建子进程的系统调用中#xff0c;一个变量接收了两个不同的返回值#xff01;通过推测也知道#xff0c;那个地址绝不是真是… 文章目录 1.进程地址空间的理解2.将虚拟地址转换为物理地址3.进程地址空间的设计4.进程地址空间的好处 1.进程地址空间的理解
在 前文 分享的fork创建子进程的系统调用中一个变量接收了两个不同的返回值通过推测也知道那个地址绝不是真是的地址物理地址而是一个虚拟的地址
在操作系统中进程所用的地址是独立的一套虚拟地址系统通过一套机制将虚拟地址映射到真正存储数据的物理地址其实在单片机或是早期的计算机都是直接操作物理地址地址的但是如果一台计算机有两个不同的进程访问同一个物理地址那么就会造成程序崩溃虚拟地址的内存管理机制就避免了这种情况让多进程运行变成了可能 我们程序所使用的内存地址叫做虚拟内存地址Virtual Memory Address实际存在硬件里面的空间地址叫物理内存地址Physical Memory Address
操作系统中通过CPU中的内存管理单元MMU 来将虚拟地址映射到物理地址当中然后再通过物理地址访问内存 如何理解 虚拟化技术是操作系统的惯用手法为进程运行分配很短毫秒级的时间片让人感绝自己的程序一直运行操作系统运行虚拟地址空间进程地址空间为进程营造一种计算机的所有内存都被自己每一个进程占有在32位的机器上4G的空间都是每个进程独占的进程之间感受不到彼此的存在 举一个生活的例子
一个富豪有十亿美金有两个私生子分别叫张三李四每个私生子之间都不知道有彼此的存在张三喜欢学习李四喜欢跑步
一天富豪就分别对两个儿子说张三啊你好好学习争取拿个诺贝尔奖我以后十个亿的家产都是你的同样的话又对李四说李四啊你好好跑步争取拿个奥运冠军我以后十个亿的家产都是你的。
我们能看出来这个富豪是个画家从例子类比到计算当中
富豪操作系统 私生子一个一个进程
富豪画的饼进程地址空间注意名词饼 生活中真正的饼物理空间
张三或李四之间感受不到彼此的存在如果他们向富豪要100万没问题但是给十个亿那显然富豪给不了
对比到操作系统也是一样一个进程不可能独占4G4G有1G的内核空间还有系统的那么多其他进程但是系统能通过这种方式很好的管理先描述再组织在Linux中进程地址空间/虚拟地址空间就是内核管理的数据结构mm_struct结构体
struct task_struct {struct mm_struct *mm, *active_mm;
}struct mm_struct
{...unsigned long total_vm, locked_vm, shared_vm, exec_vm;unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;unsigned long start_code, end_code, start_data, end_data;unsigned long start_brk, brk, start_stack;unsigned long arg_start, arg_end, env_start, env_end;...
}这里我们就可以理解fork一个变量就收两个返回值 子进程的创建会以父进程作为模板进行拷贝对于一些代码和只读的数据父子进程共享对于需要修改的数据系统使用写时拷贝的技术将需要修改的数据拷贝一份然后再对其进行修改。
这就解释了为什么一个虚拟地址或变量有两个不同的值因为同一个虚拟地址不同的进程映射到了不同的物理地址通过虚拟内存 页表映射的方式和一些写时拷贝的技术保证了进程的独立性 2.将虚拟地址转换为物理地址
这一段内容我几乎是搬运小林哥的博客 操作系统如何将虚拟地址转化成物理地址 将虚拟地址转化成物理地址主要有这两种方式内存分段和内存分页Linux系统中采用的是内存分页的方式将虚拟内存映射到物理内存当中但两种都是通过起始地址 偏移量的方式转换 内存分段 虚拟地址分为段选择因子和段内偏移量在段选择因子当中可以通过段号来找到段表中的段基地址从而获取物理地址的起始地址再通过偏移量找到对应的物理地址
内存分段的不足
第一个就是内存碎片的问题。第二个就是内存交换的效率低的问题。 内存碎片主要分为内部内存碎片和外部内存碎片 外部内存碎片 内部内存碎片
在计算机中会通过内存对齐的方式来提高计算机读取的效率比如实际的数据是5字节但是根据内存对齐分配了8字节剩下的3个字节就是内部碎片
再堆的管理当中堆内存碎片是管理的重点malloc在一定的场景下上会有许多的内存碎片问题 内存交换 内存分段管理可以做到段根据实际需求分配内存所以有多少需求就分配多大的段所以不会出现内部内存碎片。但是由于每个段的长度不固定所以多个段未必能恰好使用所有的内存空间会产生了多个不连续的小物理内存导致新的程序无法被装载所以会出现外部内存碎片的问题。
可以通过内存交换的方式解决外部碎片问题
将一些程序换出挂起在重新组织换入所谓的换出就是将程序换出到swap分区中到但是swap是磁盘会有效率的消耗。 内存分页 分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间我们叫页Page。在 Linux 下每一页的大小为 4KB。 页表是存储在内存里的内存管理单元 MMU就做将虚拟内存地址转换成物理地址的工作。
而当进程访问的虚拟地址在页表中查不到时系统会产生一个缺页异常进入系统内核空间分配物理内存、更新进程页表最后再返回用户空间恢复进程的运行。 虚拟内存如何通过分页转换成物理内存 步骤
把虚拟内存地址切分成页号和偏移量根据页号从页表里面查询对应的物理页号直接拿物理页号加上前面的偏移量就得到了物理内存地址。 简单的分页的缺陷 在 32 位的环境下虚拟地址空间共有 4GB假设一个页的大小是 4KB2^12那么就需要大约 100 万 2^20 个页每个「页表项」需要 4 个字节大小来存储那么整个 4GB 空间的映射就需要有 4MB 的内存来存储页表。
这 4MB 大小的页表看起来也不是很大。但是要知道每个进程都是有自己的虚拟地址空间的也就说都有自己的页表。
那么100 个进程的话就需要 400MB 的内存来存储页表这是非常大的内存了更别说 64 位的环境了。 多级页表 我们把这个 100 多万个「页表项」的单级页表再分页将页表一级页表分为 1024 个页表二级页表每个表二级页表中包含 1024 个「页表项」形成二级分页。如下图所示 如果使用了二级分页一级页表就可以覆盖整个 4GB 虚拟地址空间但如果某个一级页表的页表项没有被用到也就不需要创建这个页表项对应的二级页表了即可以在需要时才创建二级页表。做个简单的计算假设只有 20% 的一级页表项被用到了那么页表占用的内存空间就只有 4KB一级页表 20% * 4MB二级页表 0.804MB这对比单级页表的 4MB 是不是一个巨大的节约
程序是按需加载的在32位机器上不然小小的4G内存怎么能装的下几十G的游戏
3.进程地址空间的设计 虚拟地址在什么时候就有呢在程序加载到内存之前有没有地址 可以通过一些反汇编的工具来查看在编译好了的程序就存在了虚拟地址
objdump -afh 可执行程序结果编译器和系统之间用的是同一套进程地址空间的设计方案这样编译器和操作系统才能配合工作。 CPU在执行指令的时候用的是什么样的地址 虚拟地址 4.进程地址空间的好处
1.防止非法访问
当非法的访问或映射是操作系统都或识别并终止你的进程从而保护了物理内存。进程地址空间和页表都是由操作系统创建并维护的也就意味着使用地址空间和页表进行映射都在操作系统的监管之下如果你是非法的操作系统就会终止你的进程这也说明了进程的崩溃就是操作系统杀死了你的进程
2.内存和进程管理模块解耦
有了进程地址空间和页表映射的存在我们的数据数据代码可以映射到任意的物理内存的位置这就说明了内存管理模块和进程管理模块可以做到没有关联的关系做到了解耦合
所有在C、C语言上使用malloc函数和new的时候是在虚拟内存空间上申请的或也可是说是在进程地址空间上申请的。虽然在地址空间上申请了空间但是在物理内存甚至一个字节都不给你
因为我们申请的空间有是都并不会直接到当你真正的对物理内存进程访问的时候才会执行相关的内存管理算法帮你申请内存。
这是使用到了延迟分配的策略来提高整机的效率这是由操作系统来自动完成的对用户的继承来说完全是零感知的。
3.内存分布有序化
物理内存可以加载到任何一个地方这样几乎所有的代码和数据都是乱序的而乱序的东西是不便于管理的通过页表的存进可以将虚拟内存和物理内存一一映射站在进程的角度上所有的内存都是有序的便于管理。
请的。虽然在地址空间上申请了空间但是在物理内存甚至一个字节都不给你
因为我们申请的空间有是都并不会直接到当你真正的对物理内存进程访问的时候才会执行相关的内存管理算法帮你申请内存。