如何跨发行版可移植地获取可用内存量?

ter*_*don 12 linux memory meminfo

报告内存的标准文件/工具在不同的 Linux 发行版上似乎具有不同的格式。例如,在 Arch 和 Ubuntu 上。

  • $ free
                  total        used        free      shared  buff/cache   available
    Mem:        8169312     3870392     2648348       97884     1650572     4110336
    Swap:      16777212      389588    16387624
    
    
    $ head /proc/meminfo 
    MemTotal:        8169312 kB
    MemFree:         2625668 kB
    MemAvailable:    4088520 kB
    Buffers:          239688 kB
    Cached:          1224520 kB
    SwapCached:        17452 kB
    Active:          4074548 kB
    Inactive:        1035716 kB
    Active(anon):    3247948 kB
    Inactive(anon):   497684 kB
    
    Run Code Online (Sandbox Code Playgroud)
  • Ubuntu

    $ free
                 total       used       free     shared    buffers     cached
    Mem:      80642828   69076080   11566748    3063796     150688   58358264
    -/+ buffers/cache:   10567128   70075700
    Swap:     20971516    5828472   15143044
    
    
    $ head /proc/meminfo 
    MemTotal:       80642828 kB
    MemFree:        11565936 kB
    Buffers:          150688 kB
    Cached:         58358264 kB
    SwapCached:      2173912 kB
    Active:         27305364 kB
    Inactive:       40004480 kB
    Active(anon):    7584320 kB
    Inactive(anon):  4280400 kB
    Active(file):   19721044 kB
    
    Run Code Online (Sandbox Code Playgroud)

那么,我如何可移植地(仅跨 Linux 发行版)并可靠地获得内存量(不包括交换),供我的软件在特定时间使用?大概这就是在 Archfreecat /proc/meminfoArch的输出中显示为“可用”和“MemAvailable”的内容,但是我如何在 Ubuntu 或其他发行版中获得相同的内容?

Ste*_*itt 19

MemAvailable/proc/meminfo自 3.14 版内核起包含在内;它是由commit 34e431b0a添加的。这是您显示的输出变化的决定因素。提交消息指示如何在没有以下情况下估计可用内存MemAvailable

目前,可用于新的工作负载,而无需按下系统进入交换的内存量,可以从估计MemFreeActive(file)Inactive(file),和SReclaimable,以及“低”水印的/proc/zoneinfo

低水印是系统将交换的水平。因此,在没有MemAvailable你至少可以加起来为给出的值MemFreeActive(file)Inactive(file)SReclaimable(两者都存在于/proc/meminfo),并从减去低水印/proc/zoneinfo。后者还列出了每个区域的可用页面数,作为比较可能有用...

完整的算法在补丁中给出meminfo.c,看起来很容易适应:

  • 对所有区域的低水印求和;
  • 获取已识别的空闲内存 ( MemFree);
  • 减去低水印(我们需要避免接触它以避免交换);
  • 加入我们可以从页面缓存使用的内存量(总和Active(file)Inactive(file)):这是由页面缓存使用的内存量,减去无论是页面缓存的一半,或低水印,取其较小者;
  • 添加我们可以回收的内存量 ( SReclaimable),遵循相同的算法。

因此,将所有这些放在一起,您可以获得可用于新进程的内存:

awk -v low=$(grep low /proc/zoneinfo | awk '{k+=$2}END{print k}') \
 '{a[$1]=$2}
  END{ 
   print a["MemFree:"]+a["Active(file):"]+a["Inactive(file):"]+a["SReclaimable:"]-(12*low); 
  }' /proc/meminfo 
Run Code Online (Sandbox Code Playgroud)

  • `/proc/zoneinfo` 统计页面,`amd64` 上的页面大小大多为 4KB;您还缺少添加到页面缓存和可回收内存中的额外安全性。简化后者,我们可以将低水印减去 3 次,所以 `m-12*low` (3 × 4KB) 在我的系统上给出了正确的结果。(如果页面缓存或可回收内存小于低水位线的两倍,这种简化会低估可用内存,但无论如何您都不想在这种情况下使用太多内存,因此这似乎是一个合理的妥协。) (2认同)

cra*_*xed 7

虽然斯蒂芬的回答完全足够并且在谨慎方面犯了错误,但我决定写下包括最小比较在内的完整逻辑。信息首先从 /proc/meminfo 读取并存储在一个变量中,以便内存细节保持一致。

LOW_WATERMARK=$(awk '$1 == "low" {LOW_WATERMARK += $2} END {print LOW_WATERMARK * 4096}' /proc/zoneinfo)

MEMINFO=$(</proc/meminfo)

MEMINFO_MEMFREE=$(echo "${MEMINFO}" | awk '$1 == "MemFree:" {print $2 * 1024}')
MEMINFO_FILE=$(echo "${MEMINFO}" | awk '{MEMINFO[$1]=$2} END {print (MEMINFO["Active(file):"] + MEMINFO["Inactive(file):"]) * 1024}')
MEMINFO_SRECLAIMABLE=$(echo "${MEMINFO}" | awk '$1 == "SReclaimable:" {print $2 * 1024}')

MEMINFO_MEMAVAILABLE=$((
  MEMINFO_MEMFREE - LOW_WATERMARK
  + MEMINFO_FILE - ((MEMINFO_FILE/2) < LOW_WATERMARK ? (MEMINFO_FILE/2) : LOW_WATERMARK)
  + MEMINFO_SRECLAIMABLE - ((MEMINFO_SRECLAIMABLE/2) < LOW_WATERMARK ? (MEMINFO_SRECLAIMABLE/2) : LOW_WATERMARK)
))

if [[ "${MEMINFO_MEMAVAILABLE}" -le 0 ]]
then
  MEMINFO_MEMAVAILABLE=0
fi
Run Code Online (Sandbox Code Playgroud)

存储在变量中的结果以字节为单位。