htop показывает больше резидентного использования памяти, чем у машины

htop а также top показать больше резидентного потребления памяти, чем физической памяти, присутствующей на машине:

вывод htop:

скриншот htop

верхний вывод:

верхний скриншот

бесплатный вывод:

бесплатный скриншот

Как это вообще возможно?

Изменить 1:

вывод pmap: https://gist.github.com/ixaxaar/1571308666360f65dc66

2 ответа

Решение

Быстрый эксперимент показывает, что после разветвления RES будет считать память как родительской, так и дочерней, хотя на практике каждая страница будет совместно использоваться, пока один процесс не изменит ее или не умрет.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main ()
{
  /* 100 MiB */
  size_t size = 100 * 1024 * 1024;
  char *ptr = malloc (size);

  memset (ptr, 1, size);

  int pid = fork ();
  if (pid == 0)
  {
    puts ("Child");
  }
  else
  {
    puts ("Parent");
  }
  sleep (60);
  puts ("Bye");

  return 0;
}

Если я запускаю это, то смотрю в htop, я вижу два процесса с "100M" резидентом.

Как вы пишите в комментариях

мы делаем много ммап

вероятным объяснением является использование mmap()файлов на диске.

Репродюсер

Во-первых, создайте файл размером 2 ГБ (это также может быть разреженный файл, поэтому на самом деле он не займет 2 ГБ на диске):

      truncate --size 2G 2-gb-file

Теперь mmap с помощью Python:

test.py:

      import mmap

file = "2-gb-file"

with open(file, "r+b") as f:
  mm = mmap.mmap(f.fileno(), 0)
  print("Reading file into memory...")
  mm.read()
  input("Press Enter to finish...")

Бежать с python3 test.py.

После mm.read()прошла и возвращаемое значение (читай bytesв памяти) был GC'd, вы можете видеть, что это намного выше, чем глобальный системный Memв использовании ( 2057Mпротив 846M):

Скриншот в цвете:

Тот же скриншот в тексте:

        Mem[|||||||||||||||||||||                 846M/252G] Tasks: 62, 62 thr, 141 kthr; 1 running
  Swp[                                          0K/0K] Load average: 0.45 0.47 0.58 
                                                       Uptime: 89 days, 09:42:34

    PID USER      PRI  NI  VIRT   RES   SHR S CPU%▽MEM%  DISK READ     DISK R/W   TIME+  Command
2476802 root       20   0 2273M 2057M 2053M S  0.0  0.8    0.00 B/s    0.00 B/s  0:00.99 python3 test.py

Объяснение

Согласно https://techtalk.intersec.com/2013/07/memory-part-2-understanding-process-memory/

размер резидентного набора, то есть объем физической памяти, который ядро ​​считает назначенным процессу.

Размер резидентного набора вычисляется ядром как сумма двух счетчиков. Первый содержит количество анонимных резидентных страниц ( MM_ANONPAGES), второй — количество резидентных страниц с файловой поддержкой ( MM_FILEPAGES). Некоторые страницы могут рассматриваться как резидентные для более чем одного процесса одновременно, поэтому сумма RES может быть больше, чем объем эффективно используемой оперативной памяти, или даже больше, чем объем оперативной памяти, доступной в системе .

В этой формулировке оправданием для «большего объема оперативной памяти в системе» является «некоторые страницы могут рассматриваться для более чем одного процесса».

Но можно ли создать такую ​​ситуацию с помощью всего лишь одного процесса?

Да! Смотри ниже.

Использование большего объема памяти, чем системная память, одним процессом

Давайте повторно отобразим один и тот же файл в разные отображения памяти из разных файловых дескрипторов.

Это позволяет нам создавать произвольно много:

      import mmap

file = "2-gb-file"

open_files = []
mmaps = []

for i in range(200):
  print("Reading file into memory, iteration", i)
  f = open(file, "r+b")
  mm = mmap.mmap(f.fileno(), 0)
  mm.read()

  # Prevent GC of FD and mapping
  open_files.append(f)
  mmaps.append(mm)

input("Press Enter to finish...")

htopпоказывает, что этот единственный процесс теперь использует 400 ГБ, хотя машина имеет только 252ГБ ОЗУ:

Скриншот в цвете:

Тот же скриншот в тексте:

        Mem[|||||||||||||||||||||                1.61G/252G] Tasks: 63, 62 thr, 141 kthr; 2 running
  Swp[                                          0K/0K] Load average: 1.47 0.87 0.68 
                                                       Uptime: 89 days, 09:49:37

    PID USER      PRI  NI  VIRT   RES   SHR S CPU%▽MEM%  DISK READ     DISK R/W   TIME+  Command
2477632 root       20   0  400G  400G  400G S  0.0 158.    0.00 B/s    0.00 B/s  3:10.91 python3 test.py

Резюме

Да, используя mmapмы можем сделать RESпревышает доступную физическую память.

Для этого не обязательно использовать несколько процессов.

Другие вопросы по тегам