内存不足导致OpenStack进程异常的诊断和思考

  • 异常场景:登录OpenStack dashboard失败,检查后台服务发现数据库服务异常停止,重启发现如下申请内存不足的错误。
    mariadb
    可以看出确实内存使用不足。

  • 背景知识

定位之前先恶补下X86 32位CPU跟内存相关的知识:

Linux中大家都知道有虚拟地址空间,物理地址空间,二者是需要映射,而针对内核空间虚拟地址空间的低896M是直接可以线性映射到物理地址空间的,剩下的128M内核空间用于动态的映射896M-4G的物理地址空间,这是一个动态映射的过程。
1. Linux 物理地址空间的zone_DMA, zone_NORMAL, zone_HIGHMEM:
对于32位的CPU而言,最大寻址范围2^32 -1,也就是我们线性的4G地址空间。Linux的分段机制使其虚拟的地址空间和线性地址空间总是一致。Linux也把4G地址空间划分两部分:0-3G为用户程序地址空间,虚地址0x00000000-0xBFFFFFFF,这些空间供各个程序使用;而高位的3G-4G为内核使用的地址空间,虚拟地址从0xC0000000到0xFFFFFFFF.
这里写图片描述

从上图可知:物理地址空间的顶部以下一段空间,被PCI设备的I/O内存映射占据,它们的大小和布局由PCI规范所决定。640K~1M这段地址空间被BIOS和VGA适配器所占据。

  Linux系统在初始化时,会根据实际的物理内存的大小,为每个物理页面创建一个page对象,所有的page对象构成一个mem_map数组。

进一步,针对不同的用途,Linux内核将所有的物理页面划分到3类内存管理区中,如图,分别为ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。

  ZONE_DMA的范围是0~16M,该区域的物理页面专门供I/O设备的DMA使用。之所以需要单独管理DMA的物理页面,是因为DMA使用物理地址访问内存,不经过MMU(内存管理单元),并且需要连续的缓冲区,所以为了能够提供物理上连续的缓冲区,必须从物理地址空间专门划分一段区域用于DMA。

  ZONE_NORMAL的范围是16M~896M,该区域的物理页面是内核能够直接使用的。所谓的直接可以使用就是可以通过线性地址映射的方式即可直接访问,即把物理地址+PAGE_OFFSET的线性关系直接映射到内核空间。但是内核并没有把整个1G空间都用于线性映射,而只映射了最多的896M物理内存,预留了最高的128M虚拟地址空间给IO设备和其他用途。
  

  ZONE_HIGHMEM的范围是896M~结束,该区域即为高端内存,内核不能直接线性映射使用,需要动态映射。
  
  2. 虚拟地址空间
  这里写图片描述
  在kernel image下面有16M的内核空间用于DMA操作。位于内核空间高端的128M地址主要由3部分组成,分别为vmalloc area,持久化内核映射区,临时内核映射区。
  
3. Linux虚拟用户空间
这里写图片描述
用户进程的代码区一般从虚拟地址空间的0x08048000开始,这是为了便于检查空指针。代码区之上便是数据区,未初始化数据区,堆区,栈区,以及参数、全局环境变量。

  1. linux虚拟地址与物理地址映射的关系
    这里写图片描述
    Linux将4G的线性地址空间分为2部分,0~3G为user space,3G~4G为kernel space。

      由于开启了分页机制,内核想要访问物理地址空间的话,必须先建立映射关系,然后通过虚拟地址来访问。为了能够访问所有的物理地址空间,就要将全部物理地址空间映射到1G的内核线性空间中,这显然不可能。于是,内核将0~896M的物理地址空间一对一映射到自己的线性地址空间中,这样它便可以随时访问ZONE_DMA和ZONE_NORMAL里的物理页面;此时内核剩下的128M线性地址空间不足以完全映射所有的ZONE_HIGHMEM,Linux采取了动态映射的方法,即按需的将ZONE_HIGHMEM里的物理页面映射到kernel space的最后128M线性地址空间里,使用完之后释放映射关系,以供其它物理页面映射。虽然这样存在效率的问题,但是内核毕竟可以正常的访问所有的物理地址空间了。

重点:

所以针对32位CPU,当物理内存大于896M时,内核无法直接通过线性映射直接访问,这部分内存被称作hign memory. 相应的可以直接映射的低端物理内存叫low memory. 也就是DMA zone和Normal zone物理地址空间为low memory,这个范围之外内存叫high memory.

所谓的high memory是指物理内存空间,不是虚拟地址空间。
high memory也是被内核管理,有相应的page结构,只是没有映射到内核虚拟地址空间。当内核需要分配和访问high memory时,通过kmap从预留的128M地址空间中分配一个地址,然后动态映射到high memory,从而可以访问物理页面。high memory映射到内核地址空间一般是临时的,不是永久映射。

请一定要区分虚拟地址空间,物理地址空间,low memory high memory,896M线性地址映射和128M的动态空间映射。

用户空间的内存使用也是内核分配的, 内核有能力控制所有的硬件存储资源。

Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。

接下来结合掌握32位地址空间再补充64位地址空间内存知识:

64位地址时最大的区别就是将所有的物理地址空间都进行映射,首先, 目前大部分的操作系统和应用程序并不需要16EB( 2^64 )如此巨大的地址空间, 实现64位长的地址只会增加系统的复杂度和地址转换的成本, 带不来任何好处. 所以目前的x86-64架构CPU都遵循AMD的Canonical form, 即只有虚拟地址的最低48位才会在地址转换时被使用, 且任何虚拟地址的48位至63位必须与47位一致(sign extension). 也就是说, 总的虚拟地址空间为256TB( 2^48 ).具体几位物理地址,几位虚拟机地址可以查看:

 cat /proc/cpuinfo
 address sizes  : 46 bits physical, 48 bits virtual

然后, 在这256TB的虚拟内存空间中,前128T为用户空间,最后128T为内核空间

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值