我正在尝试检查一个进程实际上给系统带来了多少内存压力,但是ps
,top
和朋友们对此几乎毫无用处,因为他们只报告了 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
当然,运行它进行实际分析充其量也是乏味的。