精华内容
下载资源
问答
  • 内存分页机制

    万次阅读 多人点赞 2018-09-27 18:08:33
    什么要分页 在保护模式中,内存访问使用分段机制——即"段基址:段内偏移地址"的方式,为加强段内存的安全性和可管理性还引入了段描述符的概念对段内存加强管理。但仅仅这样还是不够的...

    为什么要分页

    保护模式中,内存访问使用分段机制——即"段基址:段内偏移地址"的方式,为加强段内存的安全性和可管理性还引入了段描述符的概念对段内存加强管理。但仅仅这样还是不够的,如果应用程序过多,或者内存碎片过多,又或者曾经被换出到硬盘的内存段需要再重新装载到内存,可内存中找不到合适大小的区域,要如何解决?

    内存置换

    当下大部分操作系统的方案是,将一些进程不常用的内存段换出到硬盘中,腾出内存空间供需要的进程使用。虽然硬盘是比内存还低速的设备,在两个速度不匹配的设备之间进行数据交换对内存来说是一种浪费,但使用合理的置换算法可以减少置换次数。
    在保护模式下,内存段的各种属性由段描述符保存,CPU在引用一个段时,都要先查看段描述符。段描述符存放在GDT或LDT中,即使段并不在内存中,即CPU允许在段描述表中已注册的段不在内存中存在。如果该描述符中的P位为1,表示该段在内存中存在,访问过该段后,CPU将段描述符中的A位置1,表示近期访问过该内存段。
    段描述符的A位由CPU置1,清0则由操作系统来完成。操作系统每发现该位置1后就将该位清0,同时统计一个周期内该位为1的次数,就可以知道该内存段的使用频率,从而在物理内存不足时找出使用频率最低的段将其换出到硬盘以腾出内存空间给需要使用内存的进程。当段被换出到硬盘后,操作系统将该段的段描述符的P位置0,表示该段已不在内存中。
    如上所述,计算机的软件和硬件相互配合完成内存的置换工作。虽然这在一定程度上解决了内存不足的问题,但还是有缺陷。比如物理内存特别小,以至于无法容纳任何一个进程的段,这就没法运行进程,更没法做段的置换工作了。而出现这种问题的本质原因是在目前只有分段的情况下,CPU认为线性地址等于物理地址,而线性地址是由编译器编译出来的,它本身是连续的,所以物理地址也必须要连续才行,但我们可用的物理地址并不连续。因此,为解决这个问题,我们需要解除线性地址与物理地址一一对应的关系,让他们之间重新建立映射——即让线性地址连续而物理地址不连续。在操作系统中实现这种映射的策略就是内存分页机制,相关数据结构就是页表。

    分页机制

    分页机制其实是建立在分段机制之上的。尽管在保护模式中段寄存器的内容已经是选择子,但选择子最终是为了找到段基址,因此其内存访问的核心机制仍然是“段基址:段内偏移地址”形成的绝对地址,也就是我们所说的线性地址。此线性地址在分段机制下就是物理地址,可以被CPU直接送上地址总线。分段机制下的内存访问如下图所示:
    在这里插入图片描述
    分页机制建立在分段机制的基础上,因此分页是在分段之后进行的,如下图所示:
    在这里插入图片描述
    与分段机制不同的是,在打开分页机制的情况下,“段基址:段内偏移地址”经过段部件处理后得到的线性地址就不再是物理地址了,而是虚拟地址,它是逻辑上的,是假的,还不能被送上地址总线,因为CPU必须要得到物理地址。虚拟地址对应的物理地址需要在页表中查找(由页部件自动完成)。
    分页机制的作用主要是提供连续线性地址到不连续物理地址的映射,以及用大小相等的页代替大小不等的段。由于分页机制建立在分段机制之上,即使在分页机制下也要先经过逻辑上的分段才行。每加载一个进程,操作系统按照进程中各段的起始范围,在进程自己的4GB虚拟地址空间中寻找可用空间分配内存段。接着操作系统开始为这些虚拟内存分配真实的物理内存页,它查找物理内存中可用的页,然后在页中登记这些物理页地址,这样就完成了分页机制下虚拟页到物理页的映射,每个进程都以为自己独享4GB地址空间。

    一级页表

    页是地址空间的计量单位,所以线性地址的一页也要对应物理地址的一页。一页大小为4KB,这样一来,4GB地址空间被划分为1M个页,也就是4GB空间中可以容纳1048576个页,页表中自然也要有1048576个页表项,这就是一级页表的构造。在这里插入图片描述
    一级页表的线性地址与物理地址间的映射关系是如何的呢?Linux将页表项的32位地址分为两部分,第0-11位用来表示页的大小,可以作为页内寻址;第12-31位用来表示页的数量,可以用来索引一个页。CPU中集成了用于页表寻址的硬件——页部件。
    加入一级页表后,地址转换的完整过程如下:将“段基址:段内偏移地址”传入,经段部件处理后生成线性地址,并将其传入页部件进行进一步处理。页部件将传入的线性地址分成高20位和低12位。高20位是页表的物理地址中的偏移地址部分,将其左移2位后与cr3寄存器中页表的物理地址相加后得到页表项所在的位置,从页表项中读取所映射的物理页地址;而低12位则作为物理页的页内偏移地址,将其与物理页地址相加后得到的就是最终转换成的物理地址。总的过程简述起来就是,需要得到页表项所在的物理地址,从中取出物理页的部分地址信息,从而得到物理页。

    二级页表

    一级页表解决了纯段式内存的缺陷,但自身还不够完善。例如,一级页表中所有页表项都必须要提前建好,原因是操作系统要占用4GB虚拟地址空间的高1GB,用户进程占用低3GB。且每个进程都有自己的页表,进程一多,光是为每个进程的页表分配的物理空间就不少了。
    二级页表可以很好地解决上述问题,它在一级页表上再虚拟化了一个数据结构——页目录表,来管理一级页表。因此进程可以根据需要动态创建和释放内存而不需要预先划分好空间,且每个进程都拥有的是页目录表,这样一个进程实体所占空间就进一步缩小了。
    无论是几级页表,标准页的尺寸都是4KB,所以4GB线性地址空间一共有1M个标准页。一级页表是将这1M个标准页放置到一张页表中,二级页表则是将这1M个标准页平均放置到1K(1024)个页表中,每个页表包含1K个页表项。这1K个页表则由页目录表来管理。
    页目录表的元素——页目录表项可以作为索引得到页表的物理地址。页表和页目录表本身作为一种数据结构本身要占用一定物理内存空间,但页表结构本身与其他数据混布在物理内存中,它们所占用的物理页从外在形式上与其他数据占用的物理页没有什么不同,只有CPU才能“分辨”。页表在建立之初还是相对较整洁的,随着操作系统分配和释放内存的动作越来越多,物理内存的布局就更加零散。
    在一级页表中,虚拟地址被拆分成2个部分,而由于二级页表增加了页目录表这个数据结构,因此虚拟地址被拆分成了3个部分。
    二级页表中,32位的虚拟地址中,高10位(22-31)用来在页目录表中定位一个页目录表项(PDE),PDE中有页表的物理地址。找到页表后,中间10位(12-21)则用来在页表中定位一个页表项(PTE),PTE中有分配的物理页地址。余下低12位则用于页内偏移量。
    由此我们可以得出使用二级页表的系统的完整寻址过程:(1)用虚拟地址的高10位乘4,作为页目录表内的偏移地址,加上页目录表的物理地址得到PDE的物理地址,读取PDE得到页表的物理地址。(2)用虚拟地址的中间10位乘4作为页表内的偏移地址,加上在上一步中得到的页表的物理地址,得到PTE,从PTE中读取到分配的物理页地址。(3)虚拟地址的高10位和中间10位分别是PDE和PTE的索引值,因此它们需要加以转换(左移2位),但低12位不需要左移,它直接与上一步中得到的物理页地址相加即可得到最终转换的物理地址。
    在这里插入图片描述

    页表项和页目录表项

    页表项和页目录表项的结构如下图所示:
    在这里插入图片描述
    0~11位的含义如下:
    P:Present,即存在位。若为1表示该页存在于物理内存中,若为0则表示该表不在物理内存中。
    RW:Read/Write,即读写位。为1表示可读可写,为0表示可读不可写。
    US:User/Supervisor,意为普通用户/超级用户标识位。为1表示处于User级(0、1、2、3)特权的程序都可以访问该页,为0则表示只有处于Supervisor级(0、1、2)的程序才能访问。
    PWT:Page-Level Write-Through,页级通写位。若为1表示此项采用通写方式,即表示该页不仅是普通内存,还是高速缓存,此项与快表有关。
    PCD:Page-Level Cache Disable,页级告诉缓存禁止位。若为1表示该页启用高速缓存,为0则表示禁止将该页缓存。
    A:Accessed,访问位。若为1表示该页被CPU访问过,由CPU置1,由操作系统清0。
    D,Dirty,脏页位。当CPU对一个页执行写操作时,就会设置对应页表项的D位为1,此项仅针对页表项有效,并不会修改页目录表项的D位。
    PAT:Page Attribute Table,页属性位,在页一级的粒度上设置内存属性。
    G:Global,全局位。与TLB有关,为1表示该页是全局页,该页在高速缓存TLB中一直保存。
    AVL:Available,可用位。为1表示用户进程可用该页,为0则不可用。对操作系统无效。

    快表

    分页机制实现了线性地址与物理地址的分离,它为内存管理提供了灵活性,但分页的数据结构毕竟都是存在于内存中的,相对于CPU来说内存时低速设备,因此分页无法解决I/O速度不匹配的问题。且多级页表(现代的64位操作系统已经实现了三级、四级页表的机制)的地址转换过程繁琐,涉及频繁的内存访问,这更拖慢了速度。
    因为不管是几级页表,本质上都是虚拟地址向物理地址映射,因此需要有一个“捷径”来快速获得物理地址,免去中间的查表过程——快表(Translation Lookaside Buffer,TLB)应运而生。快表基于程序的局部性原理,将进来常用的地址和指令加载到一块专门的高速缓存中,缓存中存放的条目就是虚拟地址页到物理地址页的直接映射。具体来说,TLB中的条目就是虚拟地址的高20位到物理地址高20位的映射。除此之外TLB中还有一些属性位。
    有了TLB,处理器在寻址之前就会用虚拟地址的高20位作为索引来查找TLB中的相关条目,如果匹配成功(或者成为命中)则返回虚拟地址所映射的物理页框地址,否则会走之前所属的查表流程,获得页框物理地址后再更新TLB。
    本文部分内容摘自《操作系统真象还原》,有改动

    展开全文
  • 理解什么是“大内存页”,如何进行配置,如何查看当前状态以及如何禁用它。本文中我们会详细介绍大内存页huge page,让你能够回答:Linux 中的“大内存页”是什么?在 RHEL6、RHEL7、Ubuntu 等 Linux 中,如何启用/...

    学习 Linux 中的大内存页hugepage。理解什么是“大内存页”,如何进行配置,如何查看当前状态以及如何禁用它。

    本文中我们会详细介绍大内存页huge page,让你能够回答:Linux 中的“大内存页”是什么?在 RHEL6、RHEL7、Ubuntu 等 Linux 中,如何启用/禁用“大内存页”?如何查看“大内存页”的当前值?

    首先让我们从“大内存页”的基础知识开始讲起。

    Linux 中的“大内存页”是个什么玩意?

    “大内存页”有助于 Linux 系统进行虚拟内存管理。顾名思义,除了标准的 4KB 大小的页面外,它们还能帮助管理内存中的巨大的页面。使用“大内存页”,你最大可以定义 1GB 的页面大小。

    在系统启动期间,你能用“大内存页”为应用程序预留一部分内存。这部分内存,即被“大内存页”占用的这些存储器永远不会被交换出内存。它会一直保留其中,除非你修改了配置。这会极大地提高像 Oracle 数据库这样的需要海量内存的应用程序的性能。

    为什么使用“大内存页”?

    在虚拟内存管理中,内核维护一个将虚拟内存地址映射到物理地址的表,对于每个页面操作,内核都需要加载相关的映射。如果你的内存页很小,那么你需要加载的页就会很多,导致内核会加载更多的映射表。而这会降低性能。

    使用“大内存页”,意味着所需要的页变少了。从而大大减少由内核加载的映射表的数量。这提高了内核级别的性能最终有利于应用程序的性能。

    简而言之,通过启用“大内存页”,系统具只需要处理较少的页面映射表,从而减少访问/维护它们的开销!

    如何配置“大内存页”?

    运行下面命令来查看当前“大内存页”的详细内容。

    
    
    1. root@kerneltalks # grep Huge /proc/meminfo
    2. AnonHugePages: 0 kB
    3. HugePages_Total: 0
    4. HugePages_Free: 0
    5. HugePages_Rsvd: 0
    6. HugePages_Surp: 0
    7. Hugepagesize: 2048 kB

    从上面输出可以看到,每个页的大小为 2MB(Hugepagesize),并且系统中目前有 0 个“大内存页”(HugePages_Total)。这里“大内存页”的大小可以从 2MB 增加到 1GB

    运行下面的脚本可以知道系统当前需要多少个巨大页。该脚本取之于 Oracle。

    
    
    1. #!/bin/bash
    2. #
    3. # hugepages_settings.sh
    4. #
    5. # Linux bash script to compute values for the
    6. # recommended HugePages/HugeTLB configuration
    7. #
    8. # Note: This script does calculation for all shared memory
    9. # segments available when the script is run, no matter it
    10. # is an Oracle RDBMS shared memory segment or not.
    11. # Check for the kernel version
    12. KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'`
    13. # Find out the HugePage size
    14. HPG_SZ=`grep Hugepagesize /proc/meminfo | awk {'print $2'}`
    15. # Start from 1 pages to be on the safe side and guarantee 1 free HugePage
    16. NUM_PG=1
    17. # Cumulative number of pages required to handle the running shared memory segments
    18. for SEG_BYTES in `ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"`
    19. do
    20. MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q`
    21. if [ $MIN_PG -gt 0 ]; then
    22. NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q`
    23. fi
    24. done
    25. # Finish with results
    26. case $KERN in
    27. '2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`;
    28. echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;;
    29. '2.6' | '3.8' | '3.10' | '4.1' ) echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
    30. *) echo "Unrecognized kernel version $KERN. Exiting." ;;
    31. esac
    32. # End

    将它以 hugepages_settings.sh 为名保存到 /tmp 中,然后运行之:

    
    
    1. root@kerneltalks # sh /tmp/hugepages_settings.sh
    2. Recommended setting: vm.nr_hugepages = 124

    你的输出类似如上结果,只是数字会有一些出入。

    这意味着,你系统需要 124 个每个 2MB 的“大内存页”!若你设置页面大小为 4MB,则结果就变成了 62。你明白了吧?

    配置内核中的“大内存页”

    本文最后一部分内容是配置上面提到的 内核参数 ,然后重新加载。将下面内容添加到 /etc/sysctl.conf中,然后输入 sysctl -p 命令重新加载配置。

    
    
    1. vm.nr_hugepages=126

    注意我们这里多加了两个额外的页,因为我们希望在实际需要的页面数量之外多一些额外的空闲页。

    现在,内核已经配置好了,但是要让应用能够使用这些“大内存页”还需要提高内存的使用阀值。新的内存阀值应该为 126 个页 x 每个页 2 MB = 252 MB,也就是 258048 KB。

    你需要编辑 /etc/security/limits.conf 中的如下配置:

    
    
    1. soft memlock 258048
    2. hard memlock 258048

    某些情况下,这些设置是在指定应用的文件中配置的,比如 Oracle DB 就是在 /etc/security/limits.d/99-grid-oracle-limits.conf 中配置的。

    这就完成了!你可能还需要重启应用来让应用来使用这些新的巨大页。

    转载至https://linux.cn/article-9450-1.html

    展开全文
  • 文章目录目录前文列表大页内存Linux 的大页内存的实现原理大页内存配置透明巨型 THP大页面对内存的影响大页内存的性能问题 前文列表 大页内存式虚拟存储器中,会在虚拟存储空间和物理主存空间都分割为一...

    目录

    前文列表

    大页内存

    在页式虚拟存储器中,会在虚拟存储空间和物理主存空间都分割为一个个固定大小的页,为线程分配内存是也是以页为单位。比如:页的大小为 4K,那么 4GB 存储空间就需要 4GB/4KB=1M 条记录,即有 100 多万个 4KB 的页。我们可以相待,如果页太小了,那么就会产生大量的页表条目,降低了查询速度的同时还浪费了存放页面的主存空间;但如果页太大了,又会容易造成浪费,原因就跟段式存储管理方式一般。所以 Linux 操作系统默认的页大小就是 4KB,可以通过指令查看:

    $ getconf PAGE_SIZE
    4096
    

    但在某些对性能要求非常苛刻的场景中,页面会被设置得非常的大,比如:1GB、甚至几十 GB,这些页被称之为 “大页”(Huge Page)。大页能够提升性能的主要原因有以下几点:

    • 减少页表条目,加快检索速度。
    • 提升 TLB 快表的命中率,TLB 一般拥有 16 ~ 128 个条目之间,也就是说当大页为 1GB 的时候,TLB 能够对应 16GB ~ 128GB 之间的存储空间。

    值得注意的是,首先使用大页的同时一般会禁止主存-辅存页面交换(Swap),原因跟段式存储管理方式一样,大容量交换会让辅存读写成为 CPU 处理的瓶颈。 虽然现今在数据中心闪存化的环境中,这个问题得到了缓解,但代价就是昂贵的 SSD 存储设备。再一个就是大页也会使得页内地址检索的速度变慢,所以并非是页面的容量越大越好,而是需要对应用程序进行大量的测试取得页面容量与性能的曲线峰值才对。

    启用 HugePage 的优点

    • 无需交换,不存在页面由于内存空间不足而换入换出的问题。
    • 减轻 TLB Cache 的压力,也就是降低了 CPU Cache 可缓存的地址映射压力。
    • 降低 Page Table 的负载。
    • 消除 Page Table 地查找负载。
    • 提高内存的整体性能。

    启用 HugePage 的缺点

    • HugePages 会在系统启动时,直接分配并保留对应大小的内存区域
    • HugePages 在开机之后,如果没有管理员的介入,是不会释放和改变的。

    Linux 的大页内存

    在 Linux 中,物理内存是以页为单位来管理的。默认的,页的大小为 4KB。 1MB 的内存能划分为 256 页; 1GB 则等同于 256000 页。 CPU 中有一个内置的内存管理单元(MMU),用于存储这些页的列表(页表),每页都有一个对应的入口地址。4KB 大小的页面在 “分页机制” 提出的时候是合理的,因为当时的内存大小不过几十兆字节。然而,当前计算机的物理内存容量已经增长到 GB 甚至 TB 级别了,操作系统仍然以 4KB 大小为页面的基本单位的话,会导致 CPU 中 MMU 的页面空间不足以存放所有的地址条目,则会造成内存的浪费。

    同时,在 Linux 操作系统上运行内存需求量较大的应用程序时,采用的默认的 4KB 页面,将会产生较多 TLB Miss 和缺页中断,从而大大影响应用程序的性能。当操作系统以 2MB 甚至更大作为分页的单位时,将会大大减少 TLB Miss 和缺页中断的数量,显著提高应用程序的性能。

    为了解决上述问题,自 Linux Kernel 2.6 起,引入了 Huge pages(巨型页)的概念,目的是通过使用大页内存来取代传统的 4KB 内存页面, 以适应越来越大的内存空间。Huge pages 有 2MB 和 1GB 两种规格,2MB 大小(默认)适合用于 GB 级别的内存,而 1GB 大小适合用于 TB 级别的内存。

    大页的实现原理

    为了能以最小的代价实现大页面支持,Linux 采用了 hugetlb 和 hugetlbfs 两个概念。其中,hugetlb 是记录在 TLB 中的条目并指向 hugepages,而 hugetlbfs 则是一个特殊文件系统(本质是内存文件系统)。hugetlbfs 主要的作用是使得应用程序可以根据需要灵活地选择虚拟存储器页面的大小,而不会全局性的强制使用某个大小的页面。在 TLB 中通过 hugetlb 来指向 hugepages,可以通过 hugetlb entries 来调用 hugepages,这些被分配的 hugepages 再以 hugetlbfs 内存文件系统的形式提供给进程使用

    • Regular Page 的分配:当一个进程请求内存时,它需要访问 PageTable 去调用一个实际的物理内存地址,继而获得内存空间。
      在这里插入图片描述
    • Huge Page 的分配:当系统配置 Huge pages 后,进程依然通过普通的 PageTable 来获取到实际的物理内存地址。但不同的是,在 Process PageTable 和 System PageTable 第增加了 Hugepage(HPage)属性。
      在这里插入图片描述
      可见,进程当需要使用 Huge pages 时,只需要声明 Hugepage 属性,让系统分配 PageTable 中的 Huge pages 条目即可实现。所以,实际上 Regular page 和 Huge page 是共享一个 PageTable 的,这就是所谓的以最小的代码来支持 Huge pages。

    使用 Huge pages 的好处是很明显的,假设应用程序需要 2MB 的内存,如果操作系统以 4KB 作为分页的单位,则需要 512 个页面,进而在 TLB 中需要 512 个表项,同时也需要 512 个页表项,操作系统需要经历至少 512 次 TLB Miss 和 512 次缺页中断才能将 2MB 应用程序空间全部映射到物理内存;然而,当操作系统采用 2MB 作为分页的基本单位时,只需要一次 TLB Miss 和一次缺页中断,就可以为 2MB 的应用程序空间建立虚实映射,并在运行过程中无需再经历 TLB Miss 和缺页中断(假设未发生 TLB 项替换和 Swap)。

    此外,使用 Huge pages 还能减少系统管理和处理器访问内存页的时间(扩大了 TLB 快页表查询的内存地址范围),Linux 内核中的 Swap(内存交换)守护进程也不会管理大页面占用的这部分空间。合理设置大页面能减少内存操作的负担,减少访问页表造成性能瓶颈的可能性,从而提升系统性能。由此,如果你的系统经常碰到因为 Swap 而引发的性能问题,或者你的计算机内存空间非常大时,都可以考虑启用大页内存。

    大页内存配置

    大页面配置需要连续的内存空间,因此在开机时就分配是最可靠的设置方式。配置大页面的参数有:

    • hugepages :在内核中定义了开机启动时就分配的永久大页面的数量。默认为 0,即不分配。只有当系统有足够的连续可用页时,分配才会成功。由该参数保留的页不能用于其他用途。

    • hugepagesz: 在内核中定义了开机启动时分配的大页面的大小。可选值为 2MB 和 1GB 。默认是 2MB 。

    • default_hugepagesz:在内核中定义了开机启动时分配的大页面的默认大小。

    • Step 1. 查看 Linux 操作系统是否启动了大页内存,如果 HugePages_Total 为 0,意味着 Linux 没有设置或没有启用 Huge pages。

    $ grep -i HugePages_Total /proc/meminfo
    HugePages_Total:       0
    
    • Step 2. 查看是否挂载了 hugetlbfs
    $ mount | grep hugetlbfs
    hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
    
    • Step 3. 如果没有挂载则手动挂载
    $ mkdir /mnt/huge_1GB
    $ mount -t hugetlbfs nodev /mnt/huge_1GB
    
    $ vim /etc/fstab
    nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
    
    • Step 4. 修改 grub2,例如为系统配置 10 个 1GB 的大页面
    $ vim /etc/grub2.cfg
    # 定位到 linux16 /vmlinuz-3.10.0-327.el7.x86_64 在行末追加
    default_hugepagesz=1G hugepagesz=1G hugepages=10
    

    NOTE:配置大页面后,系统在开机启动时会首选尝试在内存中找到并预留连续的大小为 hugepages * hugepagesz 的内存空间。如果内存空间不满足,则启动会报错 Kernel Panic, Out of Memory 等错误。

    • Step 5. 重启系统,查看更详细的大页内存信息
    $ cat /proc/meminfo | grep -i Huge
    AnonHugePages:   1433600 kB     # 匿名 HugePages 数量
    HugePages_Total:       0        # 分配的大页面数量
    HugePages_Free:        0        # 没有被使用过的大页面数量
    HugePages_Rsvd:        0        # 已经被分配预留但是还没有使用的大页面数目,应该尽量保持 HugePages_Free - HugePages_Rsvd = 0
    HugePages_Surp:        0        # surplus 的缩写,表示大页内存池中大于 /proc/sys/vm/nr_hugepages 中值的大页面数量
    Hugepagesize:       1048576 kB     # 每个大页面的 Size,与 HugePages_Total 的相乘得到大页面池的总容量
    

    如果大页面的 Size 一致,则可以通过 /proc/meminfo 中的 HugepagesizeHugePages_Total 计算出大页面所占内存空间的大小。这部分空间会被算到已用的内存空间里,即使还未真正被使用。因此,用户可能观察到下面现象:使用 free 命令查看已用内存很大,但 top 或者 ps 中看到 %mem 的使用总量加起来却很少。

    • Step 6. 如果上述输出看见 Hugepagesize 已经设置成 1GB,但 HugePages_Total 还是为 0,那么需要修改内核参数设定大页面的数量
    $ sysctl -w vm.nr_hugepages=10
    
    # 或者
    $ echo 'vm.nr_hugepages = 10' > /etc/sysctl.conf 
    $ sysctl -p
    

    NOTE:一般情况下,配置的大页面可能主要供特定的应用程序或服务使用,其他进程是无法共享这部分空间的(如 Oracle SGA)。 请根据系统物理内存和应用需求来设置合适的大小,避免大页面使用的浪费;以及造成其他进程因竞争剩余可用内存而出现内存溢出的错误,进而导致系统崩溃的现象。默认的,当存在大页面时,会在应用进程或者内核进程申请大页内存的时候,优先为它们分配大页面,大页面不足以分配时,才会分配传统的 4KB 页面。查看哪个程序在使用大页内存:

    grep -e AnonHugePages /proc/*/smaps | awk '{if(2>4)print0}' | awk -F "/" '{print0;system("ps−fp"3)}'
    

    透明巨型页 THP

    Transparent Huge pages(THP,透明大页) 自 RHEL 6 开始引入。由于传统的 Huge pages 很难手动的管理,对于程序而言,可能需要修改很多的代码才能有效的使用。THP 的引入就是为了便于系统管理员和开发人员使用大页内存。THP 是一个抽象层,能够自动创建、管理和使用传统大页。操作系统将大页内存看作是一种系统资源,在 THP 开启的情况下,其他的进程也可以申请和释放大页内存。

    Huge pages 和 Transparent Huge pages 在大页内存的使用方式上存在区别,前者是预分配的方式,而后者则是动态分配的方式,显然后者更适合程序使用。需要注意的是,THP 虽然方便,但在某些场景种仍然会建议我们关闭,这个需要结合实际应用场景慎重考虑。

    手动关闭 THP

    $ echo never > /sys/kernel/mm/transparent_hugepage/enabled 
    $ echo never > /sys/kernel/mm/transparent_hugepage/defrag
    
    $ cat /sys/kernel/mm/transparent_hugepage/enabled
    [always] madvise never
    
    # - [always] 表示启用了 THP
    # - [never] 表示禁用了 THP
    # - [madvise] 表示只在 MADV_HUGEPAGE 标志的 VMA 中使用 THP
    

    永久关闭 THP

    vim /etc/grub2.cfg
    
    # 在 cmdline 追加:
    transparent_hugepage=never
    

    大页面对内存的影响

    需要注意的是,为大页面分配的内存空间会被计算到已用内存空间中,即使它们还未真正被使用。因此,你可能观察到下面现象:使用 free 命令查看已用内存很大,但 top 或者 ps 指令中看到 %MEM 的使用总量加起来却很少。

    例如:总内存为 32G,并且分配了 12G 大页面的 free 如下

    [root@localhost ~]# free -g
                  total        used        free      shared  buff/cache   available
    Mem:             31          16          14           0           0          14
    Swap:             3           0           3
    

    命令 top 输出, Shift+m 按内存使用量进行排序:
    在这里插入图片描述
    命令 ps -eo uid,pid,rss,trs,pmem,stat,cmd,查看进程的内存使用量:
    在这里插入图片描述
    这种情况就导致了一个问题,如果盲目的去提高大页内存空间的占比,就很可能会出现胖的胖死,饿的饿死的问题。导致大页内存空间的浪费,因为普通程序是未必能够使用大页内存的

    大页内存的性能问题

    在页式虚拟存储器中,会在虚拟存储空间和物理主存空间都分割为一个个固定大小的页,为线程分配内存是也是以页为单位。比如:页的大小为 4K,那么 4GB 存储空间就需要 4GB/4KB=1M 条记录,即有 100 多万个 4KB 的页。我们可以相待,如果页太小了,那么就会产生大量的页表条目,降低了查询速度的同时还浪费了存放页面的主存空间;但如果页太大了,又会容易造成浪费,原因就跟段式存储管理方式一般。所以 Linux 操作系统默认的页大小就是 4KB,可以通过指令查看:

    $ getconf PAGE_SIZE
    4096
    

    但在某些对性能要求非常苛刻的场景中,页面会被设置得非常的大,比如:1GB、甚至几十 GB,这些页被称之为 “大页”(Huge Page)。大页能够提升性能的主要原因有以下几点:

    • 减少页表条目,加快检索速度。
    • 提升 TLB 快表的命中率,TLB 一般拥有 16 ~ 128 个条目之间,也就是说当大页为 1GB 的时候,TLB 能够对应 16GB ~ 128GB 之间的存储空间。

    值得注意的是,首先使用大页的同时一般会禁止主存-辅存页面交换,原因跟段式存储管理方式一样,大容量交换会让辅存读写成为 CPU 处理的瓶颈。再一个就是大页也会使得页内地址检索的速度变慢,所以并非是页面的容量越大越好,而是需要对应用程序进行大量的测试取得页面容量与性能的曲线峰值才对。

    展开全文
  • dpdk大页内存原理

    千次阅读 2019-08-16 23:56:26
    在分析dpdk大页内存的源码之前,有必要对linux内存管理的原理以及大页内存的原理有个了解,缺少这些底层基础知识,分析dpdk大页内存的源码将举步维艰。这篇文章详细介绍下linux内存管理以及大页内存的方方面面,为...

            在分析dpdk大页内存的源码之前,有必要对linux内存管理的原理以及大页内存的原理有个了解,缺少这些底层基础知识,分析dpdk大页内存的源码将举步维艰。这篇文章详细介绍下linux内存管理以及大页内存的方方面面,为分析dpdk大页内存源码扫除障碍。

    一、linux内存管理原理

    1、mmu内存管理的引入

            在没有引入mmu内存管理单元时,对于32位操作系统,每个进程都有2的32次方的地址空间(4G)。如果进程A占用内存0x1000---0x2000物理地址空间, 而进程B也占用内存0x1000---0x2000物理地址空间,这是完全有可能的。当进程A加载执行时,则进程B将不能被加载执行。一旦进程B被加载执行,则将会破坏进程A的物理地址空间。为了解决这个问题,linux操作系统和CPU都做了修改,添加了mmu内存管理。

            在引入了mmu内存管理单元后, 每个进程访问的地址不在是内存中的物理地址,而是虚拟地址。进程A被加载物理内存0x5000----0x6000物理地址空间;  进程B被加载到物理内存0x7000---0x8000物理地址空间。同时进程A与进程B各自都建立了一个虚拟地址到物理地址的映射表。 当cpu执行进程A时,会使用进程A的地址映射表,例如cpu读取0x1000虚拟地址,查询进程A的地址映射表后,发现虚拟地址映射到物理内存中的0x5000位置;当cpu执行进程B时,会使用进程B的地址映射表,例如cpu读取0x1000虚拟地址,查询进程B的地址映射表后,发现虚拟地址映射到物理内存中的0X7000位置。这样就可以避免之前提到的内存冲突问题。有了mmu内存管理单元,linux就可以轻松实现多任务了。

            地址映射表的表项是一个虚拟地址对应一个物理地址, 每个进程用于页表的维护就需要占用太多的内存空间。为此,需要修改映射方式,常用的有三种:页式、段式、段页式,这也是三种不同的mmu内存管理方式。这里主要讨论页表的实现。

    2、页表的演化

    (1)、一级页表

          上面已经讨论过了,如果每个进程的地址映射表表项存储的是每个虚拟地址到物理地址的映射,则需要消耗非常多的物理内存来维护每个进程的映射表。 因此linux系统引入了分页内存管理,分页内存管理将虚拟内存、物理内存空间划分为大小固定的块,每一块称之为一页,以页为单位来分配、管理、保护内存 , 默认一个页的大小是4K。 假设物理内存4G,物理内存一共可以划分: 4 * 1024 *1024 / 4 =  1048576个大页。对于每个进程来说, 都有一个页表,维护着虚拟地址到物理地址的转换关系。对于32位的系统来说,每个进程可寻址的逻辑地址范围0---2的32次方(4G);因此每个进程4G的逻辑地址空间也按照4K大小来划分页, 也就是1048576个页。需要注意的是每个进程的的逻辑页,是有可能映射到同一个物理页的。

            对于进程的每一个逻辑地址,低12位表示在某个页的偏移,  剩余的12---31表示这个逻辑地址处于的虚拟页号。例如:0x2009逻辑地址,0--12位值为9, 12 -- 31位值为0x2000,  每个页大小为4K, 则这个逻辑地址处于的虚拟页号为: 8192(0x2000的十进制) / 4096 = 2;   页内偏移为9。

         上面提到的虚拟地址到物理地址的映射表, 其实也就是页表。每个进程都有各自独立的页表。查询的时候就是将虚拟地址的11-31位当做虚拟页号,查找进程自己的页表, 进而找到物理内号。 然后根据虚拟地址的0-11位作为页内偏移。最后根据物理地址的计算公式:   物理地址 = 物理页号 * 4K + 页内偏移

    需要注意的是:

    1、 虚拟地址与物理地址之间不一定是一一对应的。也就是说虚拟地址0x1000不一定就映射到物理地址0x1000;   虚拟地址0x2000不一定就映射到物理地址0x2000。实际上也不可能是一一映射,操作系统维护了0-1G之间的内存空间,用于系统空间,就破坏了虚拟地址与物理地址一一对应的结构。

    2 、每个进程的虚拟地址是有可能映射到同一个物理页的, 但物理地址一定不相同。这个由mmu来保证每个进程都有自己独有的私有物理地址空间。如果不同进程虚拟地址映射到了同一个物理地址,那不就乱套了,别的进程可以修改其他进程的私有物理内存地址空间。当然了,共享内存除外,用于进程间通信。

    3、在进程申请内存空间的时候,将创建这个页表。是否有疑问,32位系统每个进程都有4G的寻址空间, 那对于物理内存一共就只有4G的空间,对于4K的分页,则每个进程的页表一共有 4 * 1024 *1024 / 4 =  1048576个条目,每个条数占用4字节,最终每个进程维护页表都需要占用:1048576 * 4 = 4194304字节, 也就是4M,那如果有几百个进程, 为了维护每个进程所需要的页表,就把内存耗光了,非常消耗资源。

           0-1G的内存空间被系统使用了, 应用进程只能申请1G以后的内存空间。如果linux内存管理机制是按照这种一级线性页表来实现, 则在进程申请内存空间时,将为进程创建所有页表项,而实际上每个进程没有占用那么多空间, 例如上面的两个进程A, B, 页表都只有3个真实使用的条目,然而linux还是会为这个进程维护4M的连续页表空间,这页表空间不能分布在内存中的不同位置。显然这个进程很多页表项都没使用,浪费了很多内存空间。 

    4、每个进程的多级页表不一定就存放到内存中,当内存不足时,是有可能被交换到磁盘swap分区中。在Linux中, kswapd是负责内核页面交换管理的一个守护进程,它的职责是保证Linux内存管理操作的高效。当物理内存不够时,它就会变得非常活跃。 kswapd 进程负责确保内存空间总是在被释放中,它监控内核中的pages_high和pages_low阀值。如果空闲内存的数值低于pages_low, 则每次 kswapd 进程启动扫描并尝试释放32个free pages.并一直重复这个过程,直到空闲内存的数值高于 pages_high

    (2) 、多级页表

            每个进程都有一个页表, 分页表有很多种实现方式,最简单的一种分页表就是把所有的对应关系记录到同一个线性列表中,即之前提到的一级页表。这种单一的连续分页表,需要给每一个虚拟页预留一条记录的位置,页表需要占用连续的内存空间,不能分布在内存中的不同位置。但对于任何一个应用进程,其进程空间真正用到的地址都相当有限。我们还记得,进程空间会有栈和堆。进程空间为栈和堆的增长预留了地址,但栈和堆很少会占满进程空间。这意味着,如果使用连续分页表,很多条目都没有真正用到,浪费很多的页表空间。因此,Linux中的分页表,最终是采用了多层的分页结构,多层的分页表能够减少所需的空间。这样有什么好处呢?可以支持更多的进程跑在系统上,直到内存不够用为止。我们以二级分页设计,用以说明Linux的多层分页表

            二级分页结构,虚拟地址将分为三部分。0-11仍然没有变化,指的是页内偏移; 将12-31位拆分为2部分,12-21为二级页表号;22-31为一级页表号。这跟字典的目录结构,或者数据库中的索引设计思想是一样的。一级页表中每个页表项key为虚拟地址的22-31位,也就是一级页表号, 而value存放的是二级页表的位置,一级页表项一共有1024个。每个二级页表中,每个页表项key为虚拟地址的12-21位,也就是二级页表号, 而value存放的是物理页号,每个二级页表项也一共有1024个。二级表有很多张,每个二级表分页记录对应的虚拟地址前10位都相同,比如二级表0x001,里面记录的前10位都是0x001

             地址查询的过程要跨越两级,需要多次查找内存。我们先取地址的前10位,也就是一级页表号,在一级页表中找到对应记录。该记录会告诉我们,目标二级页表在内存中的位置。我们接着在二级页表中,通过虚拟地址的12-21位,也就是二级页表号,找到分页记录,从而最终找到物理页号。最后根据物理地址的计算公式:   物理地址 = 物理页号 * 4K + 页内偏移

            多层分页表还有另一个优势。单层分页表必须存在于连续的内存空间。而多层分页表中的每个二级页表,可以分布在内存的不同位置,如果需要为这个进程创建一个新的二级页表,则只需要动态开辟就好了,无需预先就为这个进程开辟好所有二级页表。这样的话,操作系统就可以利用零碎空间来存储分页表。

        需要注意的是:

    1、每个进程都有一个属于自己的多级页表。

    2、每个进程的多级页表不一定就存放到内存中,在内存不足时,是有可能被交换到磁盘swap分区中。

    3、进程在申请内存空间时,系统将为这个进程创建二级页表,页表大小为真实条目大小。如果二级页表没有被使用,则这个二级页表不会被创建。

    (3)、tls查询过程

            从上面多级页表的查询中可以看出,查询虚拟地址对应的物理地址时,需要多次查找物理内存。为了加速进行虚拟地址到物理地址的映射, 减少直接查询物理内存的次数,需要将部分页表信息放到cpu高速缓存中,也就是TLB,本质上是内存中页表的一份快照。 当CPU收到应用程序发来的虚拟地址后,首先到TLB中查找相应的页表数据,如果TLB中正好存放着所需的页表项,则称为TLB命中(TLB Hit)。如果TLB中没有所需的页表项,则称为TLB未命中(TLB Miss),接下来就必须访问物理内存中存放的多级页表,同时更新TLB的页表数据

            从图中可以看出,一个32位的虚拟地址被拆分为2部分。低12位表示在页内偏移, 12---31表示这个逻辑地址处于的虚拟页号。tlb表中存放的是虚拟地址12-31位与物理页号的对应关系。例如:0x2009逻辑地址,0--12位值为9, 12 -- 31位值为0x2000,  每个页大小为4K, 则这个逻辑地址处于的虚拟页号为: 8192(0x2000的十进制) / 4096 = 2;   页内偏移为9。因此tlb表中是这么存放这个虚拟地址的: tlb某个表项中的key为2,也就是这个虚拟地址的12-31, value值为9,也就是这个虚拟地址的0-11位

    1、TLB查询过程

            当cpu需要查询某个虚拟地址对应的物理地址时,首先会查找tlb表。 根据虚拟地址的12---31查找tlb表,如果tlb表存在这个表项,则tlb命中,在这个表项中就可以找到这个虚拟地址所在的物理页号。而0-12位为虚拟地址所在的某个页的页内偏移。最后根据物理地址的计算公式:   物理地址 = 物理页号 * 4K + 页内偏移 

             如果在tlb表中查找不到这个虚拟地址对应的表项,则称为tlb miss, 也就是tlb未命中。此时会在上面提到的多级页表中进行查找,在多级页表中查找完成后,同时更新到tlb表,下一次cpu再次查询这个虚拟地址时,就可以直接在tlb表中找到了。

    2、TLB命中解释

            当tlb表中查找到相应的表项时,则称为tlb命中,否则称之为tlb未命中。在tlb未命中时,cpu将产生缺页中断,之后cpu将进行虚拟地址到物理地址的转换,最后将转换后的结果存放到tlb表中。例如:应用进程申请2M的内存空间,每个页的大小为4K,则cpu将产生2 * 1024 / 4 = 512次缺页中断,进行虚拟地址与物理地址的映射。2M一共需要512个页表记录虚拟地址与物理地址的映射,因此将这512个页表更新到tlb表中。需要注意的是tlb未命中产生缺页中断,是需要消耗性能的。

    3、TLB老化机制

            tlb表存在cpu的高速缓冲,因此tlb的大小是有限制的,通常只能存放512条虚拟地址到物理地址的转换记录。因此tlb中不可能存放所有的多级页表信息,只会存放经常被使用的那些虚拟地址。因此当tlb表项中的某个虚拟地址与物理地址的转换长时间都没有被访问了,cpu会将这条记录从tlb表中删除, 腾出空间给其他虚拟地址使用。

    4、tlb需要注意的地方

            每个进程都有属于各自的多级页表, 而tlb表只有一个,位于cpu高速缓存中。 那cpu怎么知道tlb表中存放的是哪个进程对应的虚拟地址转换信息呢? 这里会引入一个cr3页表寄存器,存放的是某个进程的一级页表的地址。当cpu对某个进程提供的虚拟地址进行转换时,会将进程的一级页表地址加载到cr3页表寄存器, tlb中存放这个进程对应的地址转换信息。这样tlb与某个进程关联起来了。

    二、为什么要使用大页内存

     (1)、未使用大页时页表占用的空间       

            以一个例子来说明为什么要使用huge page大页内存。假设32位linux操作系统上物理内存100G, 每个页大小为4K, 每个页表项占用4个字节, 系统上一共运行着2000个进程,则这2000个进程的页表需要占用多少内存呢?

            每个进程页表项总条数:               100 * 1024 * 1024k / 4k = 26214400条;

            每个进程页表大小:                       26214400 * 4 =  104857600字节 =  100M;

            2000个进程一共需要占用内存: 2000 * 100M = 200000M = 195G

            2000个进程的页表空间就需要占用195G物理内存大小, 而真实物理内存只有100G, 还没运行完这些进程,系统就因为内存不足而崩溃了,严重的直接宕机。

     (2)、使用大页时页表占用的空间 

            还是以刚才的例子来说明。假设32位linux操作系统上物理内存100G, 现在每个页大小为2M, 每个页表项占用4个字节, 系统上一共运行着2000个进程,则这2000个进程的页表需要占用多少内存呢?

            每个进程页表项总条数:               100 * 1024M /  2M = 51200条;

            每个进程页表大小:                       51200 * 4 =  204800字节 =  200K;

            2000个进程一共需要占用内存: 1 * 200k = 200K

            可以看到同样是2000个进程,同样是管理100G的物理内存,结果却大不相同。使用传统的4k大小的page开销竟然会达到
    惊人的195G;而使用2M的hugepages,开销只有200K。你没有看错,2000个进程页表总空间一共就只占用200K, 而不是2000 * 200K。 那是因为共享内存的缘故,在使用hugepages大页时, 这些大页内存存放在共享内存中, 大页表也存放到共享内存中,因此不管系统有多少个进程,都将共享这些大页内存以及大页表。因此4k页大小时,每个进程都有一个属于自己的页表; 而2M的大页时,系统只有一个大页表,所有进程共享这个大页表。

    (3)、为什么要使用大页

    1、所有大页以及大页表都以共享内存存放在共享内存中,永远都不会因为内存不足而导致被交换到磁盘swap分区中。而linux系统默认的4K大小页面,是有可能被交换到swap分区的, 大页则永远不会。通过共享内存的方式,使得所有大页以及页表都存在内存,避免了被换出内存会造成很大的性能抖动

    2、由于所有进程都共享一个大页表,减少了页表的开销,无形中减少了内存空间的占用, 使得系统支持更多的进程同时运行。

    3、减轻TLB的压力

            我们知道TLB是直接缓存虚拟地址与物理地址的映射关系,用于提升性能,省去查找page table减少开销,但是如果出现的大量的TLB miss,必然会给系统的性能带来较大的负面影响,尤其对于连续的读操作。使用hugepages能大量减少页表项的数量,也就意味着访问同样多的内容需要的页表项会更少,而通常TLB的槽位是有限的,一般只有512个,所以更少的页表项也就意味着更高的TLB的命中率

    4、减轻查内存的压力

            每一次对内存的访问实际上都是由两次抽象的内存操作组成。如果只要使用更大的页面,自然总页面个数就减少了,那么原本在页表访问的瓶颈也得以避免,页表项数量减少,那么使得很多页表的查询就不需要了。例如申请2M空间,如果4K页面,则一共需要查询512个页面,现在每个页为2M,只需要查询一个页就好了

    三、如何使用大页内存

            通常情况下,Linux默认情况下每页是4K,这就意味着如果物理内存很大,则映射表的条目将会非常多,会影响CPU的检索效率。因为内存大小是固定的,为了减少映射表的条目,可采取的办法只有增加页的尺寸。因此Hugepage便因此而来。也就是打破传统的小页面的内存管理方式,使用大页面2m,4m,16m,1G等页面大小,如此一来映射条目则明显减少。如果系统有大量的物理内存(大于8G),则无论是32位的操作系统还是64位的,都应该使用Hugepage 。来看下linux系统下如何配置大页。

    1、设置大页个数

            例如系统想要设置256个大页,每个大页2M,则将256写入下面这个文件中

    echo 256 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

    2、挂载大页

            设置完大页后,为了让大页生效,需要挂载大页文件系统。例如将hugetlbfs挂载到/mnt/huge。刚挂载完时/mnt/huge目录是空的,里面没有一个文件,直到有进程使用共享内存方式使用了这个大页系统为止,才会在这个目录下创建大页文件。

    mkdir /mnt/huge
    mount -t hugetlbfs nodev /mnt/huge

    3、查看大页信息

            查看/proc/meminf,可以看到大页信息,图中可以看出一共有256个大页,每个大页2M,剩余128个大页还没有被使用

          当使用了大页的某个程序运行时,将会在/mnt/huge目录下创建大页文件,我们可以在/mnt/huge/目录下看到所有的大页文件,一共256个。

    4、大页的使用

            当应用进程想要使用大页时,可以自己实现大页内存的使用方式,例如通过mmap, shamt等共享内存映射方式。目前dpdk通过共享内存的方式,打开/mnt/huge目录下的每个大页,然后进行共享内存映射,实现了一套大页内存使用库,来替代普通的malloc, free系统调用。或者可以使用libhugetlbfs.so这个库,来实现内存的分配与释放。进程只需要链接libhugetlbfs.so库就好了,使用库中实现的接口来申请内存,释放内存,替代传统的malloc,free等系统调用。

    四、进程如何获取虚拟地址对应物理地址

    1、在分析进程如何获取虚拟地址对应的物理地址之前,我们先来看下/proc/self目录的意义。

            我们都知道可以通过/proc/$pid/来获取指定进程的信息,例如内存映射、CPU绑定信息等等。如果某个进程想要获取本进程的系统信息,就可以通过进程的pid来访问/proc/$pid/目录。但是这个方法还需要获取进程pid,在fork、daemon等情况下pid还可能发生变化。为了更方便的获取本进程的信息,linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的系统信息,而不用每次都获取pid

    2、 任何进程可以访问/proc/self/pagemap文件,来获取虚拟地址对应的物理地址。来看下实现过程。

                                        

            pagemap文件里面每一行占用8字节,每一行记录了虚拟页号对应的物理页号。

            某个虚拟地址的虚拟页号计算公式:   virsul_page_num = 虚拟地址 / 页大小;

             在获得了虚拟地址对应的虚拟页号后,读取/proc/self/pagemap/文件中虚拟页号对应的内容file_str。这个内容的0-54位记录着虚拟页号对应的真正物理页号。那如何根据虚拟页号,在文件中找到相应位置呢? 由于文件每行占用8个字节, 用虚拟页号乘以8就是虚拟页号所在文件中的对应物理页号的位置。例如虚拟页号为2,则2 * 8 = 16。 从文件开始偏移16字节的内容就是这个虚拟地址所对应的物理页号。

            某个虚拟地址的物理页号计算公式:   phy_page_num = file_str  & 0x7fffffffffffff

            虚拟地址所在页偏移计算公式:          page_offset = 虚拟地址 % 页大小

            虚拟地址对应物理地址计算公式为:   phy_page_num * 页大小 + page_offset

            到目前为止,关于linux内存管理,虚拟内存,以及大页表等原理已经介绍完了,有了这些基础知识后,再去分析dpdk大页内存源码就容易多了, 接下里的文章将详细分析下dpdk大页内存实现

    展开全文
  • dpdk大页内存实现

    千次阅读 2019-08-18 17:32:55
    上一篇文件介绍了linux内存管理以及大页内存的原理,有了原理的支撑,接下里分析dpdk大页内存源码就轻松了,才不会云里雾里不知道在说啥。所谓的dpdk大页内存的实现,说白了就是dpdk自己实现了一套大页内存的使用库...
  • 什么是虚拟内存

    万次阅读 多人点赞 2019-11-09 15:33:02
    什么是虚拟内存呢?先查一下维基百科: 虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时...
  • 页内存原理

    千次阅读 2020-03-19 09:58:11
    我们知道,CPU是通过寻址来访问内存的。32位CPU的寻址宽度是 0~0xFFFFFFFF ,16^8 计算后得到的大小是4G,也就是说可支持的物理内存最大是4G。 但在实践过程中,碰到了这样的问题,程序需要使用4G内存,而可用物理...
  • Linux内存描述之内存页面page--Linux内存管理(四)

    万次阅读 多人点赞 2016-08-31 14:18:44
    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 ... Linux内存管理 1 前景回顾1.1 UMA和NUMA两种模型共享存储型多处理机有两种模型 均匀存储器存取(Uniform-Memory-Access,简称UMA)模型 非均匀存储器
  • 内存管理

    千次阅读 2018-10-27 15:32:54
    上篇博客分析了几种基本的内存管理模式:固定加载地址的内存管理,固定分区的内存管理,非固定分区的内存管理和交换内存管理。第一种只适合单道编程,后三种是多道编程均使用使用了同一种机制:基址与极限。 基址与...
  • 内存管理

    千次阅读 2019-03-18 20:23:54
    一、段内存管理的概念   式存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享。如果将这两种存储管理方法结合起来,就形成了段式存储管理方式。   段式管理就是将...
  • 内存的页面置换算法

    千次阅读 2018-07-20 11:15:13
    请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。 在请求分页系统中,只要求将当前需要的一部分页面装入...
  • 在介绍之前需要强调一点,大页内存也有适用范围,程序耗费内存很小或者程序的访存局部性很好,大页内存很难获得性能提升。所以,如果你面临的程序优化问题有上述两个特点,请不要考虑大页内存。后面会详细解释为啥...
  • 内存管理之:框&地址变换结构

    万次阅读 多人点赞 2018-03-19 15:01:13
    物理内存空间分为若干框(也叫作块) 分页存储管理是将作业的逻辑地址划分为一系列同等大小的部分,称为。 并为各加以编号,每个作业的的编号都是从0开始的。 框 与之类似,把可用的...
  • 如果物理内存满了也没事,把不常用的内存页先换到磁盘中,即 swap,腾出空间来就好了,到时候要用再换到内存中。 上面提到的虚拟地址也叫线性地址,简单地说就是通过绕不开的段机制得到线性地址,然后再通过分页...
  • 什么是内存内存是用于存放数据的硬件,程序执行前需要先放到内存中才能被CPU处理。 存储单元 将内存分为一个一个的小区间,每个区间就是一个存储单元。 内存地址 给内存的存储单元编地址,有两种: 按...
  • Windows内存体系(2) -- 交换文件

    万次阅读 2018-03-19 15:59:18
    一、交换文件 虚拟地址空间只是操作系统为进程“虚拟”出来的一块地址区域,并不代表任何实际的空间。而“交换文件”却对应了实际的空间,这个空间一般...从微软的官方文档来看,“虚拟内存”等于“物理内存”+...
  • 内存管理:式虚拟内存管理

    千次阅读 2019-12-17 21:00:38
    开章明意: 创建一个进程(创建进程是在磁盘中),进程以字节为单位编号,然后再进程分为许多(每4KB),内存中有对应的框(设定同)。通过页表(记录框的对应关系),将最需要的调入内存,其他留...
  • [root@lmrac1 ~]# grep Huge /proc/meminfo AnonHugePages: 0 HugePages_Total: 1236 HugePages_Free: 1236 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 0 很伤心,查文档,说如果
  • 内存页面调度、页面交换

    千次阅读 2017-07-06 14:42:25
    交换空间是专门用于临时存储内存的一块磁盘空间,通常在页面调度和交换进程数据时使用,通常推荐交换空间的大小应该是物理内存的二到四倍。 2、页面调度 页面调度是指从磁盘向内存传输数据,以及相反的过程,这个...
  • 内存设置方法

    千次阅读 2019-11-26 16:37:24
    查看系统支持哪些内存 通过查看cpu信息的flag可以看到系统是否支持内存 cat /proc/cpuinfo |grep pge ==>> 支持2MB内存 cat /proc/cpuinfo |grep pdpe1gb ==>> 支持1gb内存生效...
  • Windows内存管理方式主要分为:式管理、段式管理和段式管理 首先看一下“基本的存储分配方式”种类:   1. 离散分配方式的出现  由于连续分配方式会形成许多内存碎片,虽可通过“紧凑”功能...
  • 在操作系统中,内存管理的目的是什么呢? 其中最主要的就是提高内存的利用率,所谓的提高内存利用率,就是尽可能的在内存中多存储进程,这就涉及到为进程分配内存空间了。分配的方式主要是有两种——连续分配和离散...
  • 内存管理方式:存储、段存储、段存储非连续分配管理方式允许一个程序分散地装入到不相邻的内存分区,根据分区的大小是否固定分为分页式存储管理方式和分段式存储管理方式。分页存储管理方式中,又根据运行作业时...
  • 【操作系统 - 5】虚拟内存页面置换算法

    万次阅读 多人点赞 2017-03-21 00:37:45
    【操作系统 - 5】虚拟内存页面置换算法 --- 学习至此,发现很多学了但很久没用的知识,久而久之,慢慢遗忘。等哪天还需要的话,却发现已经忘得差不多了,即使整理了文档(word等),还是得从头再学一遍。读研第一...
  • OpenStack 高性能虚拟机之大页内存

    千次阅读 2019-06-21 18:43:54
    文章目录目录前文列表CPU 内存寻址寻址空间虚拟内存与虚拟地址内存分页大页内存Nova 的大页内存分配 前文列表 《多进程、多线程与多处理器计算平台的性能问题》 《OpenStack 高性能虚拟机之 CPU 绑定》 《OpenStack ...
  • 内存管理的三个离散方式:式(分页)、段式(分段)、段式(段联动) 目录式基本原理实现优点缺点段式管理基本原理实现优点缺点段式管理基本原理实现优点缺点 式 基本原理 将各进程的虚拟空间划分为若干...
  • 通过模拟实现请求式存储管理的几种基本页面置换算法,了解虚拟存储技术的特点,掌握虚拟存储请求式存储管理中几种基本页面置换算法的基本思想和实现过程,并比较它们的效率。 实验内容 设计一个虚拟存储区和内存...
  • DPDK-大页内存配置

    千次阅读 2020-07-14 14:08:32
    1、临时配置大页内存 1.1、临时配置2M大页内存(重启服务器后失效) 对于2 MB的页面,可以选择在系统启动后分配大页面。通过在/sys/devices/目录中的nr_hugepages文件中回显所需的大页面数来完成此操作。对于单...
  • Linux 大页内存 的使用

    千次阅读 2018-10-31 16:49:39
    Hugepage 大页内存 的使用 系统启用大页内存 下述操作,需要重启机器。 不建议 通过 设置 echo 1G > /proc/sys/vm/nr_hugepages的方式设置,因为系统不一定成功。 设置大页内存的PAGESIZE ...
  • 页内存的使用和配置

    万次阅读 2018-10-30 12:08:27
    近期公司老大让我研究大页内存,说是大页内存可以优化程序,让我根据dpdk来进行研究提升程序性能。前段时间研究dpdk中的各种机制,导致在这条路上走了许多的歪路,最后在开会的时候那么一说,卧槽,完全不对啊。需要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 809,589
精华内容 323,835
关键字:

内存页是什么