坑爹的大页内存

内存是计算机中的珍贵的稀有资源,所以为了精细管理,内存管理非常复杂的,一台计算机会同时运行很多应用,为了防止这些应用程序争抢内存,内存的管理是通过操作系统来管理的,操作系统为了方便管理内存,也为了降低应用使用内存的复杂性,引入了虚拟内存的概念( 还是那句话,解决不了的问题引入一个中间层)。

一 虚拟内存

虚拟内存,可以看成内存和磁盘的抽象,通过中断,地址翻译,内存,磁盘文件,内核软件等交互,为每个应用程序均提供一个私有的大的地址空间。

在32位系统上,虚拟内存可以访问的存储空间为:232; 64位系统中虚拟存储地址空间范围不是264,而是一般为:248,以为现在还用不了这么大的空间,可以通过命令:

[root@izbp14xswj2tx6qgnz9dllz&#xA0;~]<br>......<br>address&#xA0;sizes&#xA0;:&#xA0;46&#xA0;bits&#xA0;physical,&#xA0;48&#xA0;bits&#xA0;virtual<br>power&#xA0;management:

结果中:

address&#xA0;sizes&#xA0;:&#xA0;46&#xA0;bits&#xA0;physical,&#xA0;48&#xA0;bits&#xA0;virtual

表示物理地址为:46位,虚拟地址为48位。

这么大的空间是如何划分的那:

坑爹的大页内存

虚拟内存采用页为单位进行存储管理的,典型的页面大小为4KB或1MB,linux下可以通过getconf命令查看。页面大小顺便说一句,有些特殊的场景喜欢设置超级大页,比如在DPDK这种高性能网络处理库中,常设置大页为1GB,目的是为了减少页表的条目,可以让页表完全保存的高速缓存中,提升内存分配效率。

虚拟内存毕竟是虚的,在使用的时候系统会判断对应此虚拟内存页是否有映射的物理内存,如果没有对应的物理内存页,就会发生缺页中断,操作系统就会给这个虚拟内存页分配真正的物理内存,建立映射关系;如果现在物理内存也使用紧张,操作系统就会将不活跃的页换出存到磁盘的swap空间,将物理内存页释放出来,以供使用;如果下次换出的页面需要使用了,又会产生缺页中断,被换入到物理内存中,就这样来回倒腾,由于应用具有局部性,所以一般情况下,应用程序只在少量页面上工作,效率并不低。

[root@localhost&#xA0;~]<br>Filename&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Type&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Size&#xA0;&#xA0;&#xA0;&#xA0;Used&#xA0;&#xA0;&#xA0;&#xA0;Priority<br>/dev/dm-1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;partition&#xA0;&#xA0;&#xA0;2097148&#xA0;0&#xA0;&#xA0;&#xA0;-1<br>[root@localhost&#xA0;~]<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;total&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;used&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;free&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;shared&#xA0;&#xA0;buff/cache&#xA0;&#xA0;&#xA0;available<br>Mem:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2.8G&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;155M&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2.4G&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;9.8M&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;234M&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2.4G<br>Swap:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2.0G&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0B&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2.0G<br>[root@localhost&#xA0;~]<br>&#x6587;&#x4EF6;&#x540D;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#x7C7B;&#x578B;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#x5927;&#x5C0F;&#xA0;&#xA0;&#x5DF2;&#x7528;&#xA0;&#xA0;&#x6743;&#x9650;<br>/dev/dm-1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;partition&#xA0;&#xA0;&#xA0;2097148&#xA0;0&#xA0;&#xA0;&#xA0;-1

二 地址翻译

刚才说了,我们应用使用的是虚拟内存,真正使用的时候才会通过操作系统,MMU(内存管理单元)和存在内存中的 页表结合来完成虚拟地址和物理地址的翻译工作。页表将虚拟地址映射为物理地址,如下图:

坑爹的大页内存

实际情况要更复杂,比如分了多级页表,多级页表可以减少内存的使用,比如在x86的32位地址上通过二级页表完成地址的翻译。

这些页表是保存在内存中的,如果每次都要这么翻译,内存访问的性能肯定是受到一定影响的,数据都可以缓存,页表页同样可以进一步缓存放在SRAM中,MMU中有关于页表的缓存,小的缓存称为TLB(后备缓冲器),加入TLB后,翻译就如下图:

坑爹的大页内存

好了问题来了,TLB是一个小的缓存,保存的映射页表项毕竟是有限的。如果4GB虚拟内存空间,每个页面大小位4K,那就有220个页,如果需要4个字节来标识一个页表项的数据的话那么页表的大小就为4B*1M即4MB大小的空间。

&#x9875;&#x8868;&#x5927;&#x5C0F;=&#xA0;&#x9875;&#x8868;&#x9879;&#x4E2A;&#x6570;*&#x9875;&#x8868;&#x9879;&#x5927;&#x5C0F;

按照上图,如果我们的整个页表都可以保存到TLB中,将提升内存的访问速度,从几十到几百个时钟周期,降低到1到2个时钟周期,页表项的大小一般是固定不变的,因为TLB的大小受限,所以我们只能想办法减少页表项的个数, &#x9875;&#x8868;&#x9879;&#x7684;&#x4E2A;&#x6570;= &#x603B;&#x5185;&#x5B58;/&#x4E00;&#x4E2A;&#x5185;&#x5B58;&#x9875;&#x5927;&#x5C0F;,显然,如果我们增加内存页的大小,比如我们设置内存页大小为1GB,那么4GB的内存,只需要4个页表项,很容易将整个页表都保存在内存中,从而提升内存的访问速度。

三 大页内存

上面提到,我们为了提升内存访问速度,我们对于耗费很大的应用比如Oracle等,可以采用大页内存方式,如果程序本身使用的内存很少,采用大页内存效果不明显,还浪费内存。

3.1 查看是否支持

Linux系统采用hugetlbfs 的特殊文件系统来加入对2MB和1GB的大页内存的支持,为了配置,先查看cpu是否支持:

&#xA0;cat&#xA0;&#xA0;/proc/cpuinfo&#xA0;|grep&#xA0;--color&#xA0;pse<br>&#xA0;cat&#xA0;&#xA0;/proc/cpuinfo&#xA0;|grep&#xA0;--color&#xA0;pdpe1gb

查看内核是否支持:

&#xA0;grep&#xA0;&#xA0;-i&#xA0;hugetlb&#xA0;/boot/config-4.18.0-193.el8.x86_64&#xA0;<br>CONFIG_ARCH_WANT_GENERAL_HUGETLB=y<br>CONFIG_CGROUP_HUGETLB=y<br><br>CONFIG_HUGETLBFS=y&#xA0;<br>CONFIG_HUGETLB_PAGE=y<br>

cpu的功能列表中含有pse标识支持2MB的内存大页,含有pdpe1gb支持1GB的内存大页。

3.2 查看大页内存使用情况

grep&#xA0;Huge&#xA0;/proc/meminfo<br>AnonHugePages:&#xA0;&#xA0;&#xA0;4089856&#xA0;kB<br>ShmemHugePages:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;kB<br>HugePages_Total:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>HugePages_Free:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>HugePages_Rsvd:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>HugePages_Surp:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Hugepagesize:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2048&#xA0;kB<br>Hugetlb:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;kB

这里面说明,一个大页为: 2MB&#xFF08;Hugepagesize: 2048 kB&#xFF09;总共有的内存大页数量为: HugePages_Total: 0 NUMA架构的查看:

[root@localhost&#xA0;~]<br>Node&#xA0;0&#xA0;AnonHugePages:&#xA0;&#xA0;&#xA0;&#xA0;153600&#xA0;kB<br>Node&#xA0;0&#xA0;HugePages_Total:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Node&#xA0;0&#xA0;HugePages_Free:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Node&#xA0;0&#xA0;HugePages_Surp:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Node&#xA0;1&#xA0;AnonHugePages:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;30720&#xA0;kB<br>Node&#xA0;1&#xA0;HugePages_Total:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Node&#xA0;1&#xA0;HugePages_Free:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Node&#xA0;1&#xA0;HugePages_Surp:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>

可以看到这个NUMA机器上并没有分配大页内存:

HugePages_Total:&#xA0;0

3.3 分配大页内存

如果分配2MB的大页内存比较简单,可以通过命令预留:

<span class="hljs-built_in">echo</span>&#xA0;1024>&#xA0;/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

预留1024个2MB的大页即预留2GB的大页内存。

如果是NUMA架构,在每个node节点上预留:

<span class="hljs-built_in">echo</span>&#xA0;1024>&#xA0;/sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages<br><span class="hljs-built_in">echo</span>&#xA0;1024>&#xA0;/sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

如果要分配超过1GB的大页内存,需要在linux的启动项中设置和挂载。 1) 安装

yum&#xA0;install&#xA0;libhugetlbfs

2) 分配 更改启动文件,添加:

transparent_hugepage=never&#xA0;default_hugepagesz=1G&#xA0;hugepagesz=1G&#xA0;hugepages=4

分配4个大页内存,每个为1G,在centos6中是修改

/etc/grub.conf

centos7是修改 /etc/grub2.cfg文件. 3) mount 将大页内存映射到空目录:

mkdir&#xA0;&#xA0;&#xA0;&#xA0;/mnt/myhuge<br>mount&#xA0;-t&#xA0;hugetlbfs&#xA0;nodev&#xA0;/mnt/myhuge

如果要开机自动设置:

vim&#xA0;/etc/fstab<br>nodev&#xA0;/mnt/myhuge&#xA0;hugetlbfs&#xA0;pagesize=1GB&#xA0;0&#xA0;0

像DPDK等有专门的设置工具,开机的时候立刻设置防止内存不够,大页内存需要连续的空间。

3.4 程序使用

<br>HUGETLB_MORECORE=yes&#xA0;&#xA0;&#xA0;LD_PRELOAD=libhugetlbfs.so&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;./your_program

四 大页优缺点

优点: 1) 大页内存TLB miss 很少,缺页中断也很少,对于内存的访问性能更好,对于占用大量内存的程序,性能提升比较明显,可以提升达到50%左右。 2) 大页内存的内存页不会swap到磁盘上。

缺点: 1) 必须使用特定的方式使用,比如采用mmap映射或者通过上面方式指定。 2) 程序使用内存小,却申请了大页内存,会造成内存浪费,因为内存分配最小单位是页。

五 大页内存引起的杯具

说了半天,还没有说到大页内存引起了什么杯具那,是这样的,在一台机器上,内存本来就很小,只有4GB内存,查看程序占用内存一直没多少,当时剩余内存也很少就很奇怪。 分析下内存分配:

<br>HugePages_Total:&#xA0;&#xA0;&#xA0;&#xA0;1035<br>HugePages_Free:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1033<br>HugePages_Rsvd:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;62<br>HugePages_Surp:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>Hugepagesize:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2048&#xA0;kB

更好的工具是用atop查看,发现大页内存占用了了高达2GB的内存,却没怎么使用。

解决办法

<br>vi&#xA0;/etc/sysctl.conf<br><br>vm.nr_hugepages&#xA0;=&#xA0;0<br>vm.nr_hugepages_mempolicy&#xA0;=&#xA0;0<br><br><br>sysctl&#xA0;-p

立竿见影的效果,一下释放了2GB的内存,这可是占系统的内存一半啊,所以大页内存是否使用,还要斟酌,不然白白浪费了大量内存。

如果程序内存占用大,TLB的miss又很多的情况下,可以使用,具体如何查看TLB的miss多那,可以通过perf工具来进行分析:

perf&#xA0;record&#xA0;-e&#xA0;dTLB-loads&#xA0;-e&#xA0;faults&#xA0;-p&#xA0;pid<br>perf&#xA0;report

六 诗词欣赏

&#xA0;&#x7AF9;&#x91CC;&#x9986;&#xA0;&#xA0;-&#xA0;-&#xA0;[&#x738B;&#x7EF4;]<br><br>&#x72EC;&#x5750;&#x5E7D;&#x7BC1;&#x91CC;&#xFF0C;&#x5F39;&#x7434;&#x590D;&#x957F;&#x5578;&#x3002;<br>&#x6DF1;&#x6797;&#x4EBA;&#x4E0D;&#x77E5;&#xFF0C;&#x660E;&#x6708;&#x6765;&#x76F8;&#x7167;&#x3002;

Original: https://www.cnblogs.com/seaspring/p/14528769.html
Author: XGogo
Title: 坑爹的大页内存

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541884/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 索引有什么分类?

    索引有什么分类? – 1、主键索引:名为primary的唯一非空索引,不允许有空值。 – 2、唯一索引:索引列中的值必须是唯一的,但是允许为空值。唯一索引和…

    Java 2023年6月5日
    078
  • JAVA入门基础_从零开始的培训_JDK1.8的新特性

    JDK1.8的新特性 接口(interface)的默认方法与静态方法 lambda表达式(是一个匿名函数) 为什么需要使用lambda表达式 举个例子,创建一个线程并调用,采用匿名…

    Java 2023年6月9日
    066
  • 5.1SpringBoot整合Kafka(工具安装Kafka+Tools)

    1.工具安装Kafka 上一期我分享了安装zk,下一次我们把Kafka和可视化工具一起搞起来。 注意:这个时候ZK一定要启动成功。zk安装地址:https://www.cnblog…

    Java 2023年6月9日
    0134
  • macOs 安装了最新版的JDK怎么JDK 1.6

    因公司项目使用多个版本的JDK编译,MacOS在安装了高版本的JDK后还需要再安装低版本的JDK ,此时安装低版本的JDK 系统提示已经安装了更高版本 解决办法: 1.挂载安装文件…

    Java 2023年5月30日
    064
  • 线程池

    posted @2019-02-14 12:52 Jessica程序猿 阅读(441 ) 评论() 编辑 Original: https://www.cnblogs.com/wuc…

    Java 2023年5月30日
    091
  • 【刷题】面筋-JAVA-hashmap和hashtable

    底层都是数组+链表实现 hashMap HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增…

    Java 2023年5月29日
    083
  • Rancher证书过期查看解决

    1. rancher证书过期 1.1 现象 Rancher UI &#x65E0;&#x6CD5;&#x8BBF;&#x95EE; Rancher …

    Java 2023年6月8日
    0122
  • 队列内存限制思路防止OOM

    前几天在一个开源项目的 github 里面看到这样的一个 pr: 光是看这个名字,里面有个 MemorySafe,我就有点陷进去了。 我先给你看看这个东西: 这个肯定很眼熟吧?我是…

    Java 2023年6月13日
    083
  • Maven使用总结

    Maven使用总结 一、Maven的主要作用 Maven 翻译为”专家”、”内行”,是 Apache 下的一个纯 Java 开发的开…

    Java 2023年6月8日
    093
  • Oracle新建用户

    注:本文针对像我之前一样刚入Oracle服务器的新手,运用极简形式快速入门,更多知识,请看本人博客! 1.创建临时表空间 说明: &#x4E34;&#x65F6;&…

    Java 2023年6月8日
    085
  • Redisson报错

    org.redisson.client.RedisResponseTimeoutException: Redis server response timeout (3000 ms)…

    Java 2023年6月6日
    091
  • 基于LSM的Key-Value数据库实现WAL篇

    上篇文章简单的实现了基于LSM数据库的初步版本,在该版本中如数据写入到内存表后但还未持久化到SSTable排序字符串表,此时正好程序崩溃,内存表中暂未持久化的数据将会丢失。 引入W…

    Java 2023年6月16日
    089
  • Nginx开发从入门到精通

    团队成员 http://tengine.taobao.org/book/index.html Original: https://www.cnblogs.com/think90/p…

    Java 2023年5月30日
    091
  • Vmware 虚拟机连接外网和设置固定IP

    NAT 模式(地址转换模式) 在NAT模式中,主机网卡直接与虚拟NAT设备相连,然后虚拟NAT设备与虚拟DHCP服务器一起连接在虚拟交换机VMnet8上,虚拟机借助NAT功能,通过…

    Java 2023年6月16日
    087
  • quartz框架(九)-JobRunShell

    上篇博文,博主讲了Listener相关的内容。本篇博文,博主将要详细介绍一下JobRunShell的功能。简单的来说,JobRunShell就是Job实例运行时所在的环境,也就是说…

    Java 2023年6月7日
    086
  • K均值算法

    一、概念 K-means中心思想:事先确定常数K,常数K意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相…

    Java 2023年6月7日
    0130
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球