htop показывает больше резидентного использования памяти, чем у машины
htop
а также top
показать больше резидентного потребления памяти, чем физической памяти, присутствующей на машине:
вывод 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
превышает доступную физическую память.
Для этого не обязательно использовать несколько процессов.