malloc лениво создает отступающие страницы для выделения на Linux (и другие платформы)?

MrEngineer13 ответ на месте.

Единственное, что я хотел бы добавить, это то, что его скриншот может заставить вас поверить, что вы должны выбрать «Режим пользовательского интерфейса» из списка «Доступные квалификаторы».

Просто для пояснения: после заполнения имени Справочника и типа ресурса выберите «Ориентация» в списке «Доступные квалификаторы», и вы увидите скриншот, предоставленный MrEngineer13.

64
задан Aaron Maenpaa 26 May 2009 в 17:40
поделиться

6 ответов

Linux выполняет отложенное выделение страниц, иначе. «оптимистичное распределение памяти». Память, которую вы получаете обратно из malloc, ничем не подкрепляется, и когда вы прикоснетесь к ней, вы действительно можете получить состояние OOM (если для запрашиваемой страницы нет места подкачки), и в этом случае процесс бесцеремонно завершается .

См., Например, http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html

36
ответ дан 24 November 2019 в 16:00
поделиться

9. Память (часть Ядро Linux , Некоторые замечания по ядру Linux от Андриеса Брауэра) - хороший документ.

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

Обычно первая демонстрационная программа получает очень большой объем памяти до того, как malloc () вернет NULL. Вторая демонстрационная программа получит гораздо меньший объем памяти, поскольку фактически используется ранее полученная память. Третья программа получит такой же большой объем, что и первая программа, и затем она будет уничтожена, когда захочет использовать свою память.

Демонстрационная программа 1: выделить память, не используя ее.

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

int main (void) {
    int n = 0;

    while (1) {
        if (malloc(1<<20) == NULL) {
                printf("malloc failure after %d MiB\n", n);
                return 0;
        }
        printf ("got %d MiB\n", ++n);
    }
}

Демонстрационная программа 2: выделить память и фактически прикоснуться ко всему.

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

int main (void) {
    int n = 0;
    char *p;

    while (1) {
        if ((p = malloc(1<<20)) == NULL) {
                printf("malloc failure after %d MiB\n", n);
                return 0;
        }
        memset (p, 0, (1<<20));
        printf ("got %d MiB\n", ++n);
    }
}

Демонстрационная программа 3: сначала выделить, а потом использовать.

14
ответ дан 24 November 2019 в 16:00
поделиться

Я дал этот ответ на похожий пост на та же тема:

Некоторые распределители ленивы?

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

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

Какова цель этого? По сути, это делает маллокирование памяти более или менее постоянной по времени операцией Big O (1) вместо операции Big O (n) (аналогично тому, как планировщик Linux распределяет свою работу вместо того, чтобы делать ее одним большим фрагментом).

Чтобы продемонстрировать, что я имею в виду, я провел следующий эксперимент:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites

real    0m0.006s
user    0m0.000s
sys 0m0.008s

Программа bigmalloc выделяет 20 миллионов целых чисел, но ничего с ними не делает. deadbeef записывает по одному int на каждую страницу, в результате получается 19531 запись, а просто записывает 19531 int и обнуляет их. Как вы видите, deadbeef выполняется примерно в 100 раз дольше, чем bigmalloc, и примерно в 50 раз дольше, чем просто запись.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = malloc(sizeof(int)*20000000); // Allocate 80 million bytes

    return 0;
}

.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = malloc(sizeof(int)*20000000); // Allocate 80 million bytes

    // Immediately write to each page to simulate an all-at-once allocation
    // assuming 4k page size on a 32-bit machine.

    for (int* end = big + 20000000; big < end; big += 1024)
        *big = 0xDEADBEEF;

    return 0;
}

.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = calloc(sizeof(int), 19531); // Number of writes

    return 0;
}
9
ответ дан 24 November 2019 в 16:00
поделиться

Malloc выделяет память из блоков, управляемых libc. Когда требуется дополнительная память, библиотека переходит к ядру с помощью системного вызова brk.

Ядро выделяет вызывающему процессу страницы виртуальной памяти. Страницы управляются как часть ресурсов, принадлежащих процессу. При отключении памяти физические страницы не выделяются. Когда процесс обращается к любой ячейке памяти на одной из страниц brk'd, возникает ошибка страницы. Ядро проверяет, выделена ли виртуальная память, и приступает к сопоставлению физической страницы с виртуальной страницей.

Распределение страниц не ограничивается записью и совершенно отличается от копирования при записи. Любой доступ, чтение или запись, приводит к сбою страницы и отображению физической страницы.

Обратите внимание, что память стека отображается автоматически. То есть явное brk не требуется для отображения страниц в виртуальную память, используемую стеком.

5
ответ дан 24 November 2019 в 16:00
поделиться

В Windows страницы фиксируются (т. Е. Уменьшается доступная свободная память), но они не будут фактически выделены, пока вы не коснетесь страниц (для чтения или записи).

4
ответ дан 24 November 2019 в 16:00
поделиться

В большинстве Unix-подобных систем он управляет границей brk . Виртуальная машина добавляет страницы при ударе процессора. По крайней мере, Linux и BSD делают это.

2
ответ дан 24 November 2019 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: