Como posso obter a quantidade de memória disponível de forma portável entre as distribuições?

9

Os arquivos / ferramentas padrão que relatam memória parecem ter formatos diferentes em diferentes distribuições Linux. Por exemplo, no Arch e no Ubuntu.

  • Arch

    $ 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
    
  • 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
    

Então, como posso portar (somente através de distribuições Linux) e obter de forma confiável a quantidade de memória - excluindo swap - que está disponível para o meu software usar em um determinado momento? Presumivelmente isso é o que é mostrado como "disponível" e "MemAvailable" na saída de free e cat /proc/meminfo no Arch, mas como obtenho o mesmo no Ubuntu ou em outra distribuição?

    
por terdon 10.02.2016 / 13:53

2 respostas

11

MemAvailable está incluído em /proc/meminfo desde a versão 3.14 do kernel; foi adicionado por commit 34e431b0a . Esse é o fator determinante nas variações de saída que você mostra. A mensagem de confirmação indica como estimar a memória disponível sem MemAvailable :

Currently, the amount of memory that is available for a new workload, without pushing the system into swap, can be estimated from MemFree, Active(file), Inactive(file), and SReclaimable, as well as the "low" watermarks from /proc/zoneinfo.

As marcas d'água baixas são o nível abaixo do qual o sistema irá trocar. Portanto, na ausência de MemAvailable , você pode pelo menos adicionar os valores fornecidos para MemFree , Active(file) , Inactive(file) e SReclaimable (o que estiver presente em /proc/meminfo ) e subtrair as marcas d'água baixas de% código%. Este último também lista o número de páginas livres por zona, que podem ser úteis como comparação ...

O algoritmo completo é fornecido no patch para /proc/zoneinfo e parece razoavelmente fácil de adaptar:

  • soma as marcas d'água baixas em todas as zonas;
  • pegue a memória livre identificada ( meminfo.c );
  • subtraia a marca d'água baixa (precisamos evitar tocar nisso para evitar a troca);
  • adicione a quantidade de memória que podemos usar do cache de páginas (soma de MemFree e Active(file) ): essa é a quantidade de memória usada pelo cache de páginas, menos metade do cache de páginas ou a marca d'água baixa, o que for menor;
  • adicione a quantidade de memória que podemos recuperar ( Inactive(file) ), seguindo o mesmo algoritmo.

Então, colocando tudo isso junto, você pode obter a memória disponível para um novo processo com:

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 
    
por 10.02.2016 / 14:09
2

Enquanto a resposta de Stephen é perfeitamente suficiente e erra por precaução, decidi escrever a lógica completa incluindo as comparações mínimas. As informações são primeiro lidas de / proc / meminfo e armazenadas em uma variável para que os detalhes da memória sejam consistentes.

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

O resultado armazenado na variável é em bytes.

    
por 27.10.2016 / 00:34