当前位置: 首页 > article >正文

Linux之HugePage的原理与使用

Linux之HugePage的原理与使用

    • 虚拟地址与物理地址
      • 虚拟地址
      • 物理地址
      • 虚拟地址与物理地址的转换
    • HugePage的概念
    • Linux使用HugePage
      • 创建HugePage
      • 在程序中使用HugePage
    • 总结

虚拟地址与物理地址

在研究HugePage之前,首先需要明白虚拟地址和物理地址的概念。在计算机系统中,虚拟地址和物理地址是两个重要的概念。

虚拟地址

虚拟地址是由操作系统为每个进程分配的地址空间。每个进程都认为自己拥有独立的、连续的地址空间,从地址零开始。

  • 提供了一种内存保护机制。不同的进程有各自独立的虚拟地址空间,一个进程不能直接访问另一个进程的内存,从而防止了进程之间的非法访问和干扰。
  • 实现了多任务环境下的内存管理。操作系统可以在物理内存不足时,将部分暂时不用的页面存储到磁盘上,当需要时再重新加载到内存中,使得多个进程可以在有限的物理内存下同时运行。
  • 方便程序的编写和移植。程序员可以在不考虑实际物理内存布局的情况下进行编程,提高了开发效率。而且,由于虚拟地址空间的独立性,程序可以在不同的硬件平台上更容易地进行移植。

物理地址

物理地址是计算机内存中实际的存储单元地址。

  • 物理地址直接对应着内存中的实际存储位置,是数据真正存储的地方。
  • 硬件设备(如 CPU、内存控制器等)通过物理地址来访问内存中的数据。

虚拟地址与物理地址的转换

为了让进程能够正确地访问内存中的数据,操作系统需要将虚拟地址转换为物理地址。这个转换过程通常由硬件(如内存管理单元 MMU)和操作系统共同完成,并且需要MTT(内存转换表,Memory Translate Table)以及MPT(内存保护表,Memory Protect Table)。

  1. 当进程访问一个虚拟地址时,MMU 会根据页表等数据结构将虚拟地址转换为物理地址。
  2. 如果转换过程中发现所需的页面不在物理内存中,操作系统会触发页面错误,然后将所需的页面从磁盘加载到物理内存中,并更新页表,再次进行地址转换。

总之,虚拟地址和物理地址在计算机系统中起着不同的作用,虚拟地址为进程提供了独立的地址空间和内存保护,而物理地址则是实际存储数据的位置。通过虚拟地址到物理地址的转换,操作系统实现了高效的内存管理和多任务环境下的程序运行。
例如下图的转换所示:
在这里插入图片描述

HugePage的概念

Linux 会以页为单位管理内存,而默认的页面大小为 4KB,虽然部分处理器会使用 8KB、16KB 或者 64KB 作为默认的页面大小,不过 4KB 仍然是操作系统的默认页面配置的主流。这样一来,一个程序可能会使用很多的内存页面,而每个页面都需要相应的MTT(Memory Translate Table)和MPT(Memory Protect Table)来进行虚拟地址(VA)到物理地址(PA)的转换,当一个程序需要大量的内存时,由于每个页面都很小,就需要很多的MTT和MPT,从而会增加系统的开销,影响程序的性能。
为此,Linux中应用了大页(HugePage)的概念,也就是使用比较大的内存页面,2MB 一般都是 HugePages 的默认大小,在 arm64 和 x86_64 的架构上甚至支持 1GB 的大页面,是 Linux 默认页面大小的 262144 倍。这样,当一个应用程序需要大量的内存时,就可以只是使用非常少的内存页面就能够满足程序的需求,可以大大降低所需要的MTT和MPT,提升性能。
在这里插入图片描述
可以通过如下所示的命令查看有关HugePage的信息:

cat /proc/meminfo | grep Huge

例如如下的结果:
在这里插入图片描述
上图的结果表示,HugePage的大小为2048KB也就是2MB,现有的HugePage有两个,并且它们都没有被使用。

Linux使用HugePage

创建HugePage

首先需要在linux系统中创建HugePage,然后才可以去使用,创建并加载HugePage的命令如下所示,这里使用的时默认的大页(HugePage)大小,2MB:

  • 创建一定数量的HugePage
sudo sysctl -w vm.nr_hugepages=<HugePage 数量>
  • 挂载 HugePages 文件系统
sudo mkdir /mnt/huge
sudo mount -t hugetlbfs none /mnt/huge
  • 检查 HugePages 是否被正确使用
cat /proc/meminfo | grep Huge

也可以使用如下所示的命令查看已经挂载了的HugePage:

mount | grep hugetlbfs

其运行结果为:
在这里插入图片描述
可以看出,我创建并且挂载了两个大页。

在程序中使用HugePage

在linux中一般使用 mmap 或 shmget 来分配和使用大页需要在程序中明确地调用这些函数,并指定所需的标志和内存大小。
例如下面的示例代码,我们使用了等待用户输入字符这种方法,或者死循环的方法也可以,以便于使得程序运行很长的时间,从而我们就可以通过命令行来检验程序是否使用了大页:

hp.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    size_t hugepage_size = 2 * 1024 * 1024;  // 大页大小,2MB
    int fd = open("/mnt/huge/none", O_CREAT | O_RDWR, 0755);  // 打开大页文件系统路径

    if (fd < 0) {
        perror("Failed to open hugetlbfs");
        return 1;
    }

    // 使用 mmap 分配大页
    void *addr = mmap(NULL, hugepage_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, fd, 0);
    
    if (addr == MAP_FAILED) {
        perror("mmap failed");
        return 1;
    }

    // 向大页写入数据
    strcpy((char *)addr, "Hello, Huge Page!");
    printf("Huge page allocated at: %p\n", addr);
    printf("Data in huge page: %s\n", (char *)addr);  // 读取并打印数据

    // 程序运行,等待输入以退出
    printf("Press Enter to exit...");
    getchar();

    // 使用完毕后,记得释放内存
    munmap(addr, hugepage_size);
    close(fd);

    return 0;
}

对代码进行编译:

gcc -o hpt hp.c

运行程序:

sudo ./hpt

在这里插入图片描述

为了验证我们的程序是否使用了指定的大页,我们首先查看程序的进程:

ps aux | grep hpt

命令行运行之后的结果为:
在这里插入图片描述
这里需要注意,真正使用了大页的是中间那行所表示的进程号,这是由于第一行的进程号是原始的c程序的进程,在其中我们开启了一个调用大页,所以会重新开启一个进程,最后那一行的进程可以不用管,与我们的大页示例程序无关,如果非要去深究一下,那么,它实际上表示的是对应的那个大页分配给了我们的这个程序。

这里记录一下程序运行的pid,我的就是169136,后续在使用的时候需要替换为你自己的pid。

然后我们再次运行下面的命令:

cat /proc/meminfo | grep Huge

结果为:
在这里插入图片描述
可以看出来,空闲的HugePage只有一个,实际上非空闲的那个HugePage正在被我们的程序使用。

在前面我们已经得到了程序的pid,现在就使用这个pid直接去查看程序所使用的页面,命令行如下所示:

sudo cat /proc/<pid>/smaps | grep -i Private_Hugetlb

例如我的命令就是:

sudo cat /proc/169136/smaps | grep -i Private_Hugetlb

得到的结果为:
在这里插入图片描述
可以看出,的确使用了一个大小为2048KB也就是2MB的大页HugePage。

至此,我们成功使用了大页并对其进行了验证,可以关闭之前的那个程序了。

总结

本文介绍了虚拟地址、物理地址、地址转换、大页(HugePage)等概念,并在linux中创建大页,然后还使用c语言编写程序真实地使用了HugePage并且对其使用情况进行了检验和分析。希望本文对大家有所帮助和启发。


http://www.kler.cn/a/350337.html

相关文章:

  • Decode Global专注金融创新,构建便捷的交易平台
  • 使用 Tauri 开发桌面应用程序:新一代的轻量解决方案
  • cuda从零开始手搓PB神经网络
  • TOSUN同星TsMaster使用入门——3、使用系统变量及c小程序结合panel面板发送报文
  • 2024又是一年的CSDN之旅-总结过去展望未来
  • 如何用3个月零基础入门网络安全?_网络安全零基础怎么学习
  • 国家基本药物目录数据库查询3种方法(2018、2012、2009年版)
  • 无人机之定高算法篇
  • ThinkPHP5bootstrapMySQL开发学习平台(包括后台管理功能、PC端网页、移动端网页)手把手运行源码
  • 树莓派5 spi控制
  • 如何用好 CloudFlare 的速率限制防御攻击
  • 藏式建筑彩绘知识图谱展示及问答
  • 【Next.js 项目实战系列】02-创建 Issue
  • 010集——关于图层( 新建图层、获取图层名)(CAD—C#二次开发入门)
  • 中国是全球最大的硫酸锰生产和消费地区
  • 实现vlan间的通信
  • C/C++复习(三)
  • Web自动化Demo-PHP+Selenium
  • 一个Idea:爆改 T480
  • 51单片机的土壤湿度检测控制系统【proteus仿真+程序+报告+原理图+演示视频】
  • Java 日志打印
  • 【网络安全】注册流程:电子邮件验证绕过
  • 2024/10/12 力扣 15.三数之和
  • PHP系统中502 的原因及解决方法
  • HC32F460KETA PETB JATA 工业 自动化 电机
  • Redis集群和哨兵环境下节点故障排查命令