如何获取进程的实际内存使用情况(包括交换区中的数据)

如何获取进程的实际内存使用情况(包括交换区中的数据)

我正在尝试检查一个进程实际上给系统带来了多少内存压力,但是pstop和朋友们对此几乎毫无用处,因为他们只报告了 3 个统计数据:

  • RES- 常驻内存集仅包括物理内存中的数据页(不包括换出的页),但也包括加载的共享库。
  • VIRT- 包括内核映射到内存的所有页面,包括换出的页面,还包括内存映射文件、共享库等。
  • SHR- 可能是最无用的,仅包括可以共享的库使用的内存,但据我了解,它实际上并没有考虑进程使用的内存,而是计算库的整个大小,即使只是其中的一部分它实际上是居民。

在多进程计算软件中,我想知道通过运行或终止与现有进程具有相似或相同共享内存/库的另一个进程将使用/释放多少内存,这意味着我需要知道数据集有多大进程使用的 - 包括所有换出的数据页,但不包括所有非数据页,例如共享库、共享内存页、内存映射文件等。

top我并不害怕某些编码,但如果已经有一个我不知道的替代品显示了该信息,那就更好了。

答案1

看看这个脚本https://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py我们经常使用它来调试我们的应用程序。这不是一个简单的任务,有时不同内核的方法也不同。

从脚本的描述中您可以阅读以下内容。

# Try to determine how much RAM is currently being used per program.
# Note per _program_, not per process. So for example this script
# will report RAM used by all httpd process together. In detail it reports:
# sum(private RAM for program processes) + sum(Shared RAM for program processes)
# The shared RAM is problematic to calculate, and this script automatically
# selects the most accurate method available for your kernel.

答案2

我认为您可以分析每个相关进程的 /proc/ID/maps 文件 - 如果列出所有映射页面,则丢弃所有可执行页面、共享页面和未映射到 inode 的页面。如果您将它们的大小相加(可以从开始和结束地址计算),那么结果就是进程的实际内存压力。

我得到了以下 PoC ruby​​ 代码来执行此操作:

sudo ruby -le '
  puts $<.read.split("\n").collect{|l|l.split(/\s+/)}. # create data records
    select{|r|r[4].to_i==0&&r[1]!~/x|s/}. # remove mapped, exec and shared pages
    collect{|r|b,e=r[0].split(/-/,2).collect{|a|a.to_i(16)};r[0]=e-b;r}. # size
    inject(0){|s,r|s+=r[0]} # sum
  ' /proc/17099/maps

当然,运行它进行实际分析充其量也是乏味的。

相关内容