Подтвердить что ты не робот

Максимальная память, которую malloc может выделять

Я пытался выяснить, сколько памяти я могу в максимальной степени использовать на своей машине (1 Гб оперативной памяти 160 Гб платформы HD Windows).

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

Кроме того, когда программа превышает потребление памяти на определенный уровень, компьютер перестает работать, потому что другие приложения не получают достаточное количество памяти, которое им требуется.

Итак, чтобы подтвердить, я написал небольшую программу в C:

int main(){  
    int *p;
    while(1){
        p=(int *)malloc(4);
        if(!p)break;
    }   
}

Я надеялся, что будет время, когда распределение памяти завершится неудачно, и цикл сломается, но мой компьютер висел, поскольку это был бесконечный цикл.

Я ждал около часа, и, наконец, мне пришлось отключить компьютер.

Некоторые вопросы:

  • Предоставляет ли malloc также память из HD?
  • В чем причина такого поведения?
  • Почему в любой момент времени не прерывался цикл?
  • Почему не было отказа в распределении?
4b9b3361

Ответ 1

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

Неверно: большинство компьютеров/ОС поддерживают виртуальную память, поддерживаемую дисковым пространством.

Некоторые вопросы: malloc также выделяет память с жесткого диска?

malloc запрашивает ОС, что, в свою очередь, может использовать некоторое дисковое пространство.

В чем причина такого поведения? Почему в любой момент цикл не прерывался?

Почему не было отказа в распределении?

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

Когда программа превышает потребление памяти на определенном уровне, компьютер перестает работать, потому что другие приложения не получают достаточное количество памяти, которое им требуется.

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

Ответ 2

Я знаю, что эта ветка устарела, но для тех, кто хочет дать ей попробовать себя, используйте этот код, отрезанный

#include <stdlib.h>

int main() {
int *p;
while(1) {
    int inc=1024*1024*sizeof(char);
    p=(int*) calloc(1,inc);
    if(!p) break;
    }
}

run

$ gcc memtest.c
$ ./a.out

при запуске этот код заполняет одну RAM, пока не будет убит ядром. Использование calloc вместо malloc для предотвращения "ленивой оценки". Идеи, взятые из этой темы: Вопросы памяти Malloc

Этот код быстро заполнил мою оперативную память (4 ГБ), а затем примерно через 2 минуты мой раздел подкачки 20 ГБ до его смерти. 64-разрядный Linux, конечно.

Ответ 3

malloc выполняет собственное управление памятью, управляет небольшими блоками памяти, но в конечном итоге использует для выделения памяти функции Win32 кучи. Вы можете думать о malloc как "реселлере памяти".

Подсистема памяти Windows содержит физическую память (RAM) и виртуальную память (HD). Когда физическая память становится недостаточной, некоторые страницы могут быть скопированы из физической памяти в виртуальную память на жестком диске. Windows делает это прозрачно.

По умолчанию виртуальная память включена и будет потреблять доступное пространство на HD. Таким образом, ваш тест будет продолжаться до тех пор, пока он не выделит весь объем виртуальной памяти для процесса (2 ГБ на 32-битных окнах) или не заполнит жесткий диск.

Ответ 4

Попробуйте это

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

main() {
    int Mb = 0;
    while (malloc(1<<20)) ++Mb;
    printf("Allocated %d Mb total\n", Mb);
}

Включите в него stdlib и stdio.
Этот экстракт взят из глубоких секретов.

Ответ 5

Я действительно не знаю, почему это не удалось, но стоит отметить, что `malloc (4)" на самом деле не может дать вам 4 байта, поэтому этот метод не является точным способом найти максимальный размер кучи.

Я нашел это из своего вопроса здесь.

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

Ответ 6

В соответствии со стандартом C90, вы можете получить хотя бы один объект размером 32 кбайт, и это может быть статическая, динамическая или автоматическая память. C99 гарантирует не менее 64 Кбайт. Для любого более высокого предела обратитесь к документации вашего компилятора.

Кроме того, аргумент malloc является size_t, а диапазон этого типа - [0, SIZE_MAX], поэтому максимум, который вы можете запросить, - SIZE_MAX, значение которого зависит от реализации и определяется в <limits.h>.

Ответ 7

/proc/sys/vm/overcommit_memory контролирует максимум в Linux

Например, в Ubuntu 19.04 мы легко видим, что malloc реализован с помощью mmap(MAP_ANONYMOUS с помощью strace.

Затем man proc затем описывает, как /proc/sys/vm/overcommit_memory контролирует максимальное распределение:

Этот файл содержит режим учета виртуальной памяти ядра. Значения:

  • 0: эвристический overcommit (по умолчанию)
  • 1: всегда слишком часто, никогда не проверяйте
  • 2: всегда проверяйте, никогда не переусердствуйте

В режиме 0 вызовы mmap (2) с MAP_NORESERVE не проверяются, и проверка по умолчанию очень слабая, что приводит к риску получения процесса "OOM-kill".

В режиме 1 ядро делает вид, что памяти всегда достаточно, пока память фактически не исчерпается. Одним из вариантов использования этого режима являются научные вычислительные приложения, которые используют большие разреженные массивы. В версиях ядра Linux до 2.6.0 любое ненулевое значение подразумевает режим 1.

В режиме 2 (доступно с Linux 2.6) общее виртуальное адресное пространство, которое может быть выделено (CommitLimit в /proc/meminfo), рассчитывается как

CommitLimit = (total_RAM - total_huge_TLB) * overcommit_ratio / 100 + total_swap

where:

  • total_RAM - общий объем оперативной памяти в системе;
  • total_huge_TLB - объем памяти, выделенный для огромных страниц;
  • overcommit_ratio - это значение в /proc/sys/vm/overcommit_ratio; и
  • total_swap - это объем пространства подкачки.

Например, в системе с 16 ГБ физической ОЗУ, 16 ГБ подкачки, без места, выделенного для огромных страниц, и overcommit_ratio, равным 50, эта формула дает CommitLimit 24 ГБ.

Начиная с Linux 3.14, если значение в /proc/sys/vm/overcommit_kbytes отлично от нуля, вместо этого CommitLimit рассчитывается следующим образом:

CommitLimit = overcommit_kbytes + total_swap

См. также описание /proc/sys/vm/admiin_reserve_kbytes и /proc/sys/vm/user_reserve_kbytes.

Documentation/vm/overcommit-accounting.rst в дереве ядра 5.2.1 также дает некоторую информацию, хотя и немного меньше:

Ядро Linux поддерживает следующие режимы обработки overcommit

  • 0 Эвристическая обработка overcommit. Очевидные злоупотребления адресом пространство отказано. Используется для типичной системы. Это обеспечивает серьезно дикое распределение не удается, в то же время позволяя уменьшить использование свопа. корню разрешено выделять чуть больше память в этом режиме. Это значение по умолчанию.

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

  • 2 Не переусердствуйте. Общая фиксация адресного пространства для Система не может превышать своп + настраиваемую сумму (по умолчанию 50%) физической памяти. В зависимости от суммы вы использовать, в большинстве случаев это означает, что процесс не будет убит при доступе к страницам, но получит ошибки в памяти распределение в зависимости от ситуации.

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

Минимальный эксперимент

Мы можем легко увидеть максимально допустимое значение с помощью:

main.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char *chars;
    size_t nbytes;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 2;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }

    /* Allocate the bytes. */
    chars = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );

    /* This can happen for example if we ask for too much memory. */
    if (chars == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Free the allocated memory. */
    munmap(chars, nbytes);

    return EXIT_SUCCESS;
}

GitHub upstream.

Скомпилируйте и запустите, чтобы выделить 1 ГБ и 1 ТБ:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out 0x40000000
./main.out 0x10000000000

Затем мы можем поиграть со значением распределения, чтобы увидеть, что позволяет система.

Я не могу найти точную документацию для 0 (по умолчанию), но на моей машине с 32 ГБ ОЗУ не разрешается выделение 1 ТБ:

mmap: Cannot allocate memory

Если я включу неограниченный overcommit, однако:

echo 1 | sudo tee /proc/sys/vm/overcommit_memory

тогда распределение 1TiB работает нормально.

Режим 2 хорошо документирован, но мне лень выполнять точные расчеты, чтобы проверить это. Но я просто укажу, что на практике нам разрешено выделять около:

overcommit_ratio / 100

от общего объема ОЗУ, а по умолчанию overcommit_ratio - 50, поэтому мы можем выделить около половины общего объема ОЗУ.

VSZ против RSS и убийца нехватки памяти

Пока что мы только что выделили виртуальную память.

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

Я проиллюстрировал это подробно на: Что такое RSS и VSZ в управлении памятью Linux

Ответ 8

когда вы в первый раз назначаете какой-либо размер на * p, каждый раз, когда вы оставляете эту память незаписанной. Это означает

в то время, когда ваша программа выделяет только память объемом 4 байта

. то как вы можете использовать всю оперативную память, поэтому SWAP-устройство (временное пространство на жестком диске) не обсуждается. Я знаю алгоритм управления памятью, в котором, когда ни одна программа не ссылается на блок памяти, этот блок имеет право выделять для запроса памяти программ. Вот почему вы просто продолжаете работать с Драйвером RAM и почему он не может дать возможность обслуживать другие программы. Кроме того, это болтающаяся проблема сравнения.

Ans: Вы можете в наибольшей степени распределить память вашего размера RAM. Поскольку никакая программа не имеет доступа к устройству подкачки.

Надеюсь, у вас все вопросы получат удовлетворительные ответы.