使用RAMMap+PoolMon分析Windows内存使用异常问题

本文介绍了微软Sysinternals工具RAMMap和PoolMon在Windows内存管理中的应用,尤其是在分析内核模式下内存分配时的重要性。通过案例研究,作者展示了如何使用这些工具解决WindowsServer2016虚拟机内存异常增长的问题,最终确定是VMwareTools驱动版本过低导致的。
摘要由CSDN通过智能技术生成

由于技术能力有限,文章仅能进行简要分析和说明,如有不对的地方,请指正,谢谢🙂。

1 RAMMap和PoolMon工具简介

RAMMap和PoolMon都是微软Sysinternals的工具,前者可以从使用类型、页列表、进程、文件、优先级,以及物理地址来检查内存的使用情况,但是无法检查尚未提交和分页的进程内存使用情况;后者可以是作为RAMMap的补充,可以检查系统分页和非分页的缓冲池内存使用情况,并且提供了按照驱动程序的角度来查看其内存使用情况。

可以说RAMMap可以详细分析用户模式下进程的内存分配情况,但对于内核模式下的内存分配,还是要使用PoolMon来详细分析。

关于RAMMap的微软介绍:RAMMap - Sysinternals | Microsoft Learn

关于PoolMon的微软介绍:PoolMon - Windows drivers | Microsoft Learn

2 Windows内存分配说明

Windows操作系统使用来分配和管理内存,并将多个物理内存页组成一片虚拟地址空间,物理内存页是不连续的,而虚拟地址空间是连续的。应用程序正是使用了一片连续的虚拟地址来访问物理内存中不连续的内存页,并且由处理器完成虚拟地址和物理地址之间的转换。

处理器根据不同的应用程序代码在用户模式和内核模式些切换,用户模式运行的是notepad.exe、calc.exe这类应用程序,每个应用程序的虚拟地址空间都是独立的,称为“用户空间”,如果一个应用程序发生故障,其他应用程序和操作系统不受崩溃的影响;内核模式包含了核心系统组件和驱动程序,所有代码共享单个虚拟地址空间,称为“系统空间”,如果内核模式驱动程序发生故障,整个操作系统就会发生故障。

而在系统空间里面,又有两个可以动态分配内存的区域:分页缓冲池和非分页缓冲池,分页缓冲池的内存可以被调出到磁盘(发生swap),但是非分页缓冲池的区域是无法调出到磁盘(无法swap)一直占用着内存。

内核模式下的核心系统组件或者驱动程序可以同时使用分页缓冲池和非分页缓冲池的空间,记住如果使用了对于非分页缓冲区,则是固定在物理内存中,无法swap的。

 3 案例分享

有一台Windows Server 2016的服务器,运行在VMware vSphere虚拟化平台上,平台版本为6.7,每间隔1周左右,虚拟机就会出现内存异常增长,且通过操作系统自带的任务管理器、资源管理器均无法找到消耗内存的具体进程信息,并且也使用了杀毒软件进行扫描,没有发现异常程序。

  1. 虚拟化平台监控到内存异常增长。

  2. 任务管理器显示消耗最大内存空间的为dwm.exe进程,实际上才占用134252KB。

  3. 杀毒软件扫描结果,没有发现任何异常信息。

3.1 使用RAMMap分析内存的整体分配情况

RAMMap不需要额外安装,在RAMMap - Sysinternals | Microsoft Learn下载传到服务器上运行即可。

  1. 解压后在文件夹中找到RAMMap64(64位操作系统),双击打开。

  2. 发现99%的内存都被分配到了NonPaged Pool

结合前文对Windows内存的分配说明,Nonpaged Pool是属于内核模式下的系统空间,这篇区域的内存基本被操作系统的核心组件和驱动程序所使用,而那就需要使用PoolMon继续分析Nonpaged Pool的具体使用情况。

3.2 使用PoolMon分析非分页缓冲池的使用情况

PoolMon包含在Windows 驱动程序工具包 (WDK) 的 \Tools\Other 子目录中,微软并没有提供单独的工具下载,而WDK工具的安装需要联网,服务器又处于内网环境无法访问互联网。后面经过测试,可以找一台可联网的机器安装WDK工具,在WDK安装目录下的\Tools\x64 子目录找到poolmon.exe拷贝出来,例如我安装到了C:\Program Files (x86)\Windows Kits\10\Tools\x64目录下。

接下来就是使用PoolMon分析非分页缓冲池的详细使用情况了:

  1. 打开cmd,在poolmon.exe所在目录,直接执行.\poolmon.exe -p -b,可以看到消耗最多内存空间是VFil和VNet。(这里因为显示不全,暂不)

  2. 检查操作系统补丁情况,发现只有安装操作系统时自带的补丁,未再安装其它更新。

  3. 检查虚拟化平台的BUG情况,暂未发现直接关联的,但是在一篇KB(https://kb.vmware.com/s/article/2077302)中找到了关联的问题,VFil和VNet可能是VMware Tools的驱动,并且要求升级VMware Tools到10.0.8以上,而虚拟机所安装的VMware Tools版本是12.0.0,故基本可以排除是这个BUG。

我们已经通过PoolMon定位到消耗内存资源的罪魁祸首是vFIL和vNET,由于VMware Tools的版本比KB中说明的版本要高,暂不考虑升级VMware Tools。

由于该问题是可复现的(基本上运行了一周左右就会出现这个情况),沟通处理该问题的解决方案时,采用了排除法:

  1. 考虑先对操作系统安装最新的补丁。
  2. 如果操作系统补丁无效,则说明不是由于操作系统自身原因,再考虑升级VMware Tools。

最后通过观察,确认是安装了当时操作系统最新的补丁后解决了这个问题。

总结:工欲利其事,必先利其器。需要对所解决的事情涉及的理论和内容有一定的了解,才能够正确地使用工具来解决问题。

上一篇硬件时钟和系统时钟的同步机制及案例分享

下一篇Prometheus监控之SNMP Exporter介绍和数据展现

缓存作为内存(cache as RAM)是一种将计算机缓存作为虚拟内存使用的方法,这种方法通常用于嵌入式系统或其他资源受限的环境中。下面是一个使用缓存作为内存的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #define MEM_SIZE 4096 #define CACHE_SIZE 1024 int main(int argc, char *argv[]) { int fd = open("/dev/mem", O_RDWR); if (fd == -1) { perror("open"); exit(1); } void *mem = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { perror("mmap"); exit(1); } void *cache = mem; // 使用缓存作为内存 // 使用缓存作为内存进行读写操作 int *data = (int *) cache; for (int i = 0; i < CACHE_SIZE; i++) { data[i] = i; } // 将缓存的内容写回到实际内存中 if (msync(mem, MEM_SIZE, MS_SYNC) == -1) { perror("msync"); exit(1); } if (munmap(mem, MEM_SIZE) == -1) { perror("munmap"); exit(1); } if (close(fd) == -1) { perror("close"); exit(1); } return 0; } ``` 在这个示例代码中,我们通过使用 `mmap` 函数将 `/dev/mem` 文件映射到程序的内存中,然后将缓存指针设置为映射的内存指针,从而实现了缓存作为内存的目的。在示例代码中,我们将缓存大小设置为 1024,实际内存大小设置为 4096,因此我们只能使用缓存中的一部分来存储数据。如果我们要访问实际内存中未映射的部分,可能会导致程序中断或发生其他问题。因此,在使用缓存作为内存时需要格外小心,确保不会访问到未映射的内存区域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值