[linux][memory]hugetlb和hugepage技术分析

前言: 乍一看,hugetlb和hugepage还挺像的,好像都是所谓的“大页”。然而,却很难说出来它们的差异。作者也是花了写时间翻翻代码,写了几个测试的例子,加上用工具据实测了几个关键参数,才明白。 分析: 1,page fault 用户大多数情况下申请内存的方法: a,使用malloc函数族,其实是glibc封装了brk/mmap。这种情况下分配的是虚拟内存,并没有直接分配物理内存。 b,调用brk分配,这种情况很少见,并只分配虚拟内存。 c,使用mmap,分配出来虚拟内存。如果flags带有MAP_POPULATE,则直接分配物理内存,否则不分配物理内存。 d,使用mlock,则mlock指定的地址空间内,要分配物理内存。 上述的几种情况中,其实大多数情况下,都是只分配虚拟内存,并不分配物理内存。 对于这种情况,在CPU访问到没有分配物理内存的地址的时候,MMU会产生exception(这个exception就是page fault),kernel处理page fault,如果访问的地址合法,权限合法,则分配相应的物理内存。 2,2M page size 例如进程分配了4G的虚拟内存,那么,就会产生4G / 4K = 1M次page fault。 如果page size变大呢?page size为2M的情况下,会产生4G / 2M = 2K次page fault。 相比之下,减少了很多次page fault。换言之,就是节省了好多计算量,节省了处理page fault的CPU资源。 这里还有一个问题,为什么是2M,而不是其他呢?原因是在x86上,一个pmd能管理的内存是2M。 3,hugetlb shell中敲cat /proc/meminfo | grep -i HugePage:

可以看到,Hugepace的大小事2048K,即2M。当前没有HugePages的total,free等。 执行:echo 1024 > /proc/sys/vm/nr_hugepages

通过修改/proc/sys/vm/nr_hugepages,来控制kernel中的HugePages的数量。 在执行mmap函数中,flags带着MAP_HUGETLB则分配2M的page。 这里需要注意的是,HugePages不在buddy system中继续管理了,在修改echo 1024 > /proc/sys/vm/nr_hugepages的前后对比,也会发现,系统中的free memory减少了2G。 那么问题来了,如果buddy system中没有那么多连续的2M会怎么样呢?会分配出问题。所以需要在开机的时候,就分配大量的2M page。最差情况就是,2M page有很多剩余,而操作系统的free memory很少。 hugetlb的主要逻辑代码在linux-4.0.4/mm/hugetlb.c中,VM_HUGETLB的宏定义数值是0x00400000。 再需要说明一点,hugetlb标记的vma,是不能做ksm/uksm的。 4,hugepage linux提供函数int madvise(void *addr, size_t length, int advice); 其中advice有MADV_HUGEPAGE。 先看madvise,其实就是advise类型的,并非强制的。设定了MADV_HUGEPAGE的地址空间,可以在smaps中查到hg标记。 敲命令cat /proc/PID/smaps可以看到:

查看当前系统的hugepage的策略:cat /sys/kernel/mm/transparent_hugepage/enabled:

一共三种,always,madvise,never。修改的话,也同样:echo “always” > /sys/kernel/mm/transparent_hugepage/enabled 关于hugepage的代码,主要在linux-4.0.4/mm/huge_memory.c中实现。大意是,如果是hugepage的vma发生了page fault,则尽量使用2M的page来分配,如果分配失败,则使用普通的page(4K)来分配。同时,还有一个后台内核线程khugepaged,周期性扫描vma,如果kernel中有了2M的page,会尽量 使用2M page替换4K page。M_HUGEPAGE的宏定义是0x20000000。可见,和HUGETLB还是不同的。另外,hugepage是可以做ksm的。 5,test 作者写了一段简单的代码: #include <sys/mman.h> #include <sys/time.h> #include <stdio.h> #include <string.h> #define SIZE ((size_t)1024*1024*1024*1) int main(int argc, char *argv[]) { void *p = NULL; struct timeval starttv, endtv; int ret = 0; size_t index = 0; p = mmap(NULL, SIZE, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) { perror("mmap"); return 0; } if (argc == 2) { printf("madvise\n"); ret = madvise(p, SIZE, MADV_HUGEPAGE); if (ret < 0) { perror("madvise"); return 0; } } getchar(); ret = gettimeofday(&starttv, NULL); if (ret < 0) { perror("gettimeofday starttv"); return 0; } for (index = 0; index < SIZE; index += 4096) *((int*)(p + index)) = 0xc5; ret = gettimeofday(&endtv, NULL); if (ret < 0) { perror("gettimeofday starttv"); return 0; } printf("time cost : %ld\n", (endtv.tv_sec - starttv.tv_sec) * 1000000 + endtv.tv_usec - starttv.tv_usec); getchar(); return 0; } 先不要在意没有执行munmap的那段~: 编译:gcc hugepace.c -o hugepage 执行:a,./hugepage看执行时间 b, ./hugepage huge看执行时间

实验结果上来看,确实减少了执行时间。 6,perf 上面看到了执行时间的变少,再来看看具体的原因。 perf是性能分析的首选。 启动上述的测试程序hugepage,会停留在第一个getchar()位置上,这时候,敲:perf record -e page-faults -p PID;等到函数执行完,会在perf的shell里面生成perf.data文件;敲:perf report: 两次的结果分别是:

可见,page-faults的差别还是有很大差别。 7,/sys/kernel/mm/transparent_hugepage/enabled 前文提到过,这个参数有三个,当使用always的时候,其实kernel不在乎是否vma带有了VM_HUGEPAGE选项,都会优先使用2M page的。这里需要注意一下。 后记: 关于hugepage和hugetlb的代码,这里没有仔细分析,原因是代码比较繁杂,作者也只是大概看了逻辑,没完全看透。 从使用的角度来说,作者并不欣赏hugetlb,首先会划出去很多内存,让内存管理复杂化,诚然会让大块连续内存分配的情况下性能有所提高,不过看实验结果也没那么明显,还要牺牲挺多高级特性。而hugepage则好很多,非强制,hugepage使用的内存也是在buddy system的管理框架内。 网上有人说使用hugetlb会加速CPU访问内存的速度,作者并不清楚,也没想到一个好的办法来实验。期待有朋友给出来好办法或者数据。

原文发布于微信公众号 - AlwaysGeek(gh_d0972b1eeb60)

原文发表时间:2017-03-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏咸鱼不闲

jsp与数据库的面对面交流

前言:要完成数据的交互的一种方式就是jsp+jsp+数据库。下面就来演示一个用jsp展示数据库内的图片的小例子。

1173
来自专栏同步博客

搭建MySQL高可用负载均衡集群

  使用MySQL时随着时间的增长,用户量以及数据量的逐渐增加,访问量更是剧增,最终将会使MySQL达到某个瓶颈,那么MySQL的性能将会大大降低。这一结果也不...

3996
来自专栏java一日一条

数据库的读写分离

读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务...

1723
来自专栏魏艾斯博客www.vpsss.net

修改 WordPress 数据库默认表前缀 wp_ 的方法

新手使用 wordpress 初期,数据库默认表前缀用的都是 wp_,从理论上来说对博客安全性不好。所以说我们正式搭建博客的时候都会把默认 wp_ 改为别的,比...

2342
来自专栏快乐八哥

PHP+MySQL代码部署在Linux(Ubuntu)上注意事项

最近帮同学做一个网站,同学买的是阿里云服务器,Linux发行版是Ubuntu12.04。我在本地把程序写好,都调试好了。然后他让我自己发布和部署。之前在大学里上...

43910
来自专栏蓝天

Linux后台开发常用工具

pwdx - report current working directory of a process,格式:pwdx pid 内存分析工具 v...

1632
来自专栏我是攻城师

ElasticSearch入门介绍之会当凌绝顶(一)

3675
来自专栏杨建荣的学习笔记

使用pt工具检测MySQL主从延迟(r12笔记第7天)

今天翻看了下《高性能MySQL》,真是让人拍手称绝,里面的很多实战思路非常不错,各种问题分析如数家珍,如果是有一定基础的同学,看起来会非常不错。 当然里...

4676
来自专栏王磊的博客

微信中通过页面(H5)直接打开本地app的解决方案

简述 微信中通过页面直接打开app分为安卓版和IOS版,两个的实现方式是完全不同的。 安卓版实现:使用腾讯的应用宝,只要配置了“微下载”之后,打开链接腾讯会帮你...

55513
来自专栏CodeSheep的技术分享

前后端分离实践:基于vue实现网站前台的权限管理

2897

扫码关注云+社区

领取腾讯云代金券