Понимание распределения памяти - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь понять, "как работает память".Насколько я понимаю, ОС (в моем случае Linux) при вызове mmap для создания MAP_ANONYMOUS сопоставления создает:

mmap() создает новое сопоставление в виртуальном адресном пространствевызывающий процесс

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

Также, насколько я знаю, происходит фактическое сопоставление с физической памятью.когда CPU вызывает сбой страницы, когда он пытается получить доступ к странице памяти, которой еще нет в таблице страниц.

ОС отлавливает ошибку страницы и создает запись в каталоге страницы.

Что должно произойти , если я mmap отредактировал некоторую анонимную память (но не коснулся какой-либостраниц), затем другие процессы исчерпали всю физическую память, и затем я пытаюсь использовать одну из страниц mmap ed (у меня отключен обмен)?

Процессор должен вызвать сбой страницы, а затем попытаться создать запись в каталоге страниц.Но поскольку физической памяти не осталось, она не сможет этого сделать ...

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Прежде всего, если вы отключите swap (вы не добавляете раздел подкачки), это не означает, что вы не используете swap.Читайте ниже.

Вы можете запустить систему без дополнительного пространства подкачки, но это не значит, что вы не используете виртуальную память.Вы не можете отключить виртуальную память, и виртуальная память является фундаментальной концепцией для реализации mmap(2) syscall.

mmap(2) использует файл для заполнения начального содержимого страниц, которые он использует для сегмента памяти.Но он делает больше ... Он использует обычную виртуальную память для выделенных страниц этого сегмента и заменяет их, когда ядру нужны некоторые из этих страниц.Поскольку существует файл для хранения содержимого страницы, вам не нужно его менять, просто запишите содержимое страницы в нужное место в файле.Как и в случае, когда другой процесс, к которому присоединен тот же сегмент совместно используемой памяти, одна и та же страница отображается в обоих процессах, когда один процесс записывает страницу, другой видит ее немедленно.Кроме того, если какой-либо процесс читает или записывает файл, так как используемый блок является тем же блоком, что и для чтения файла на диске, данные, которые он собирается увидеть, представляют собой одни и те же данные, используемые обоими процессами.Вот как это работает.

Ядро экономит много подкачки с помощью этого механизма, а также это позволяет ядру иметь возможность отбрасывать части текстового сегмента программы без необходимости менять их навспомогательное устройство (поскольку они уже находятся в текстовом сегменте файла для программы)

Когда вы говорите

Что должно произойти, если я создал анонимную память (но не коснулся ни одной изстраницы) ...

если вы не коснулись ни одной из страниц, то, вероятно, ни одна из них еще не была отображена на самом деле, только ресурс готов к использованию, но еще не подготовленвыделены.Это когда вы ошибаетесь на одной из этих страниц (например, для чтения, вы обещали не трогать их), страница отображается на реальной странице памяти, но резервная копия диска (или место подкачки для нее) фактически находится в файле, а нев устройстве подкачки.Эта страница также фактически является дисковым блоком (точнее набором дисковых блоков), используемым для хранения данных из драйвера диска, поэтому не используются несколько копий одних и тех же данных.

EDIT

Anonymous mmap(2), вероятно, использует также дисковые блоки (в некоторых дисках по умолчанию).Так что даже в том случае, если вы не используете устройство подкачки, возможно, вам разрешено использовать mmap(2) с виртуальным пространством, сопоставленным с дисковым дескриптором.Я не проверял это, но старые каналы Unix работали таким образом.Для этого можно использовать временный индекс (без записи, размещенной в каталоге, например, стертые файлы с открытым процессом).

0 голосов
/ 14 февраля 2019

Для использования mmap (MAP_ANONYMOUS) или malloc в вашем случае ничего не изменится, если вам не хватает свободной памяти mmap возвращает MAP_FAILED и malloc возвращает NULL

Если я использую эту программу:

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
  int n = atoi(argv[1]);
  void * m;

  if (argc == 1) {
    m = mmap(NULL, n1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    if (m == MAP_FAILED) {
      puts("ko");
      return 0;
    }
  }
  else {
    m = malloc(n*1024*1024);
    if (m == 0) {
      puts("ko");
      return 0;
    }
  }

  puts("ok");
  getchar();

  char * p = (char *) m;
  char * sup = p + n*1024*1024;

  while (p < sup) {
    *p = 0;
    p += 512;
  }

  puts("done");
  getchar();

  return 0;
}

Я на raspberrypi с 1 Гб памяти и подкачкой 100Mo,память уже используется хром , потому что я на SO

proc/meminfo дает:

MemTotal:         949448 kB
MemFree:          295008 kB
MemAvailable:     633560 kB
Buffers:           39296 kB
Cached:           360372 kB
SwapCached:            0 kB
Active:           350416 kB
Inactive:         260960 kB
Active(anon):     191976 kB
Inactive(anon):    41908 kB
Active(file):     158440 kB
Inactive(file):   219052 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        102396 kB
SwapFree:         102396 kB
Dirty:               352 kB
Writeback:             0 kB
AnonPages:        211704 kB
Mapped:           215924 kB
Shmem:             42304 kB
Slab:              24528 kB
SReclaimable:      12108 kB
SUnreclaim:        12420 kB
KernelStack:        2128 kB
PageTables:         5676 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      577120 kB
Committed_AS:    1675164 kB
VmallocTotal:    1114112 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:           8192 kB
CmaFree:            6796 kB
*1024* Если я это сделаю:
pi@raspberrypi:/tmp $ ./a.out 750
ko

750 слишком большой, но

pi@raspberrypi:/tmp $ ./a.out 600 &
[1] 1525
pi@raspberrypi:/tmp $ ok

Используемая память ( top и т. Д.) Не отражает 600Mo, потому что я не читаю / пишу в них

proc/meminfo дает:

MemTotal:         949448 kB
MemFree:          282860 kB
MemAvailable:     626016 kB
Buffers:           39432 kB
Cached:           362860 kB
SwapCached:            0 kB
Active:           362696 kB
Inactive:         260580 kB
Active(anon):     199880 kB
Inactive(anon):    41392 kB
Active(file):     162816 kB
Inactive(file):   219188 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        102396 kB
SwapFree:         102396 kB
Dirty:               624 kB
Writeback:             0 kB
AnonPages:        220988 kB
Mapped:           215672 kB
Shmem:             41788 kB
Slab:              24788 kB
SReclaimable:      12296 kB
SUnreclaim:        12492 kB
KernelStack:        2136 kB
PageTables:         5692 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      577120 kB
Committed_AS:    2288564 kB
VmallocTotal:    1114112 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:           8192 kB
CmaFree:            6796 kB

И я снова могу сделать

pi@raspberrypi:/tmp $ ./a.out 600 &
[2] 7088
pi@raspberrypi:/tmp $ ok

pi@raspberrypi:/tmp $ jobs
[1]-  stopped                 ./a.out 600
[2]+  stopped                 ./a.out 600
pi@raspberrypi:/tmp $ 

Даже сумма слишком велика для памяти + подкачка, /proc/meminfo дает:

MemTotal:         949448 kB
MemFree:          282532 kB
MemAvailable:     626112 kB
Buffers:           39432 kB
Cached:           359980 kB
SwapCached:            0 kB
Active:           365200 kB
Inactive:         257736 kB
Active(anon):     202280 kB
Inactive(anon):    38320 kB
Active(file):     162920 kB
Inactive(file):   219416 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        102396 kB
SwapFree:         102396 kB
Dirty:                52 kB
Writeback:             0 kB
AnonPages:        223520 kB
Mapped:           212600 kB
Shmem:             38716 kB
Slab:              24956 kB
SReclaimable:      12476 kB
SUnreclaim:        12480 kB
KernelStack:        2120 kB
PageTables:         5736 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      577120 kB
Committed_AS:    2876612 kB
VmallocTotal:    1114112 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:           8192 kB
CmaFree:            6796 kB

Если я запишу в память% 1, затем остановлю его, у меня есть много операций подкачки на флэш-памяти

pi@raspberrypi:/tmp $ %1
./a.out 600

done
^Z
[1]+  stopped                 ./a.out 600

, теперь почти нет свободного свопа и почти нет свободной памяти, /proc/meminfo дает

MemTotal:         949448 kB
MemFree:           33884 kB
MemAvailable:      32544 kB
Buffers:             796 kB
Cached:            66032 kB
SwapCached:        66608 kB
Active:           483668 kB
Inactive:         390360 kB
Active(anon):     462456 kB
Inactive(anon):   374188 kB
Active(file):      21212 kB
Inactive(file):    16172 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        102396 kB
SwapFree:           3080 kB
Dirty:                96 kB
Writeback:             0 kB
AnonPages:        740984 kB
Mapped:            61176 kB
Shmem:             29288 kB
Slab:              21932 kB
SReclaimable:       9084 kB
SUnreclaim:        12848 kB
KernelStack:        2064 kB
PageTables:         7012 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      577120 kB
Committed_AS:    2873112 kB
VmallocTotal:    1114112 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:           8192 kB
CmaFree:            6796 kB

% 1 все еще вайна getchar , если я делаю то же самое для% 2, это работает, но на самом деле, потому что процесс% 1 исчезает (без сообщения в оболочке)

Поведение такое же, если я malloc (давая второй аргумент программе)


См. Также Какова цель флага MAP_ANONYMOUS в системном вызове mmap?

...