zoukankan      html  css  js  c++  java
  • Linux 进程地址空间及原理

      1.程序地址空间

           首先,我们先看学c/c++时候学到的程序内存布局:

               

      准确地说,程序地址空间其实就是进程的地址空间,实际就是pcb中的mm_struct

            

      接下来,我们用fork()演示一下进程的地址空间。

       //父子进程数据独有demo 
    1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 5 int g_val = 10; 6 int main() 7 { 8 int pid=fork(); 9 if(pid < 0) 10 { 11 return -1; 12 }else if(pid == 0) 13 { 14 //child 15 g_val = 100; 16 printf("child val: %d--%p ",g_val,&g_val); 17 } 18 else 19 { 20 //parent 21 sleep(1); 22 printf("parent val:%d--%p ",g_val,&g_val); 23 } 24 return 0; 25 }

          很容易看出,父子进程的地址是一样的,但是变量的值却不一样。

          由此能推出 : 我们所看到的地址并不是真实的物理地址

              Linux下,我们称作为虚拟地址

           说明进程访问的地址都是虚拟地址,物理地址我们用户是看不到的,由操作系统负责物理地址和虚拟地址的转换

      

       2.进程地址空间实现原理 --- 利用内存碎片

        通过上面测试,我们肯定要问,为什么要使用虚拟地址呢?

        1.增加内存访问控制 --- 如果进程可以使用任意的物理内存,意味着如果木马病毒进来了,就可以修改内存空间让电脑瘫痪,很不安全。

           2.提高内存利用率 --- 如何利用内存碎片,榨干计算机性能,一直是计算机发展史中的一个重要问题,下面会给大家讲讲如何提高内存利用率。

                3.保证进程独立性 --- 用物理地址的话,地址难以确定,有了虚拟地址,进程都可以拥有自己的一套虚拟地址,能让程序员更好地编码。

        既然虚拟地址这么好用,那来看看它的实现原理吧!

           在Linux下,OS使用的是分页式内存管理

           内存分页: 

          为什么要有分页 --- 物理地址和虚拟地址的分离,给进程带来了安全和便利,但是他们之间的转换如果是按字节一一对应记录的,那么要消耗的额外资源就太多了

          分页是什么 --- 以更大尺寸的单位页来管理内存,这个单位页负责物理地址与虚拟地址的映射关系,Linux中通常每页大小为4KB。下面是我Linux下测出的大小。

           分页的原理 --- 因为物理页和虚拟页内地址肯定是连续的,所以页内数据可以按顺序一一对应。

                   因为页表大小都是一样的,所以页内数据的末尾地址都是相同的(二进制下后12位都为1),我们把这个地址称之为偏移量。

                   偏移量实际上表达了该字节在页内的位置。

                   地址的前一部分则是页编号,后一部分是页内偏移。

                 页表记录页编号和物理块编号的对应关系。

                   虚拟页编号在页表中找到对应的物理块编号,再计算出页内偏移,就可得到实际物理地址。

                 物理地址 = 块编号*块大小 + 偏移量 

           分页优化: 多级分页表 ---  分页让我们将逻辑地址和物理地址分离,能更好的进行内存管理。

                       我们知道进程都会有一套虚拟内存地址(mm_struct),那么其中肯定包含了分页表保存所有分页,为了保证查询效率,分页表会保存于内存中。

                       并且,堆栈上有很多空间都是进程预留的,意味着如果使用连续分页表,很多条目都没有真正用到

                       因此,Linux中的分页表,采用了多层的数据结构多层的分页表能够减少所需的空间

                      

                       用上图的二级表结构举个例子,页编号被分为两级:

                           一级表: 一级页编号保存地址的前8位(十六进制2位),一级表负责映射该地址下的二级表地址。

                         二级表: 二级表编号保存地址的后12位(十六进制3位),二级表负责映射该地址下的物理地址。

                      上面我们了解到,连续的分页表可以直接通过虚拟页编号找到物理页编号,而二级分页表,我们要先拿出虚拟页编号前8位编号在一级表中找到对应的二级表,再拿出虚拟页编号后12位在二级表找到对应的物理地址。就像身份证号,每个地区的前6位都是一样的,如果要查某人的身份证号,先查地区,再查人,能大大减少查找量,如上图0x01为空,说明这个地区没人,那么相应的二级表也不需要存在。这样,二级表所占数据就会比连续单页表少多了

                      二级表还有一个优点: 因为是多层结构,所以不必像单层表一样占据一整块内存,而是可以存于不同位置,提高内存利用率。

          

                      

     

      

          

                

          

           

            

        

      

       

     

     

          

           

           

         

         

         

  • 相关阅读:
    再次或多次格式化导致namenode的ClusterID和datanode的ClusterID之间不一致的问题解决办法
    Linux安装aria2
    POJ 3335 Rotating Scoreboard 半平面交
    hdu 1540 Tunnel Warfare 线段树 区间合并
    hdu 3397 Sequence operation 线段树 区间更新 区间合并
    hud 3308 LCIS 线段树 区间合并
    POJ 3667 Hotel 线段树 区间合并
    POJ 2528 Mayor's posters 贴海报 线段树 区间更新
    POJ 2299 Ultra-QuickSort 求逆序数 线段树或树状数组 离散化
    POJ 3468 A Simple Problem with Integers 线段树成段更新
  • 原文地址:https://www.cnblogs.com/Duikerdd/p/11670292.html
Copyright © 2011-2022 走看看