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

Каков самый большой объем памяти, который я могу выделить на моем MacBook Pro?

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

Этот простой код на С++ выделяет буфер (размером 1024 байта), присваивает последние пять символов буфера, отчеты, а затем удаляет буфер. Затем он удваивает размер буфера и повторяется до тех пор, пока не сработает.

Если мне что-то не хватает, код может выделить до 65 терабайт памяти, прежде чем он завершится с ошибкой на моем MacBook Pro. Возможно ли это? Как он может выделять столько памяти, сколько у меня на машине? Я должен пропустить что-то простое.

int main(int argc, char *argv[])
{
        long long size=1024;
        long cnt=0;
        while (true)
        {
                char *buffer = new char[size];
                // Assume the alloc succeeded. We are looking for the failure after all.

                // Try to write to the allocated memory, may fail
                buffer[size-5] = 'T';
                buffer[size-4] = 'e';
                buffer[size-3] = 's';
                buffer[size-2] = 't';
                buffer[size-1] = '\0';

                // report
                if (cnt<10)
                        cout << "size[" << cnt << "]: " << (size/1024.) << "Kb ";
                else if (cnt<20)
                        cout << "size[" << cnt << "]: " << (size/1024./1024.) << "Mb ";
                else
                        cout << "size[" << cnt << "]: " << (size/1024./1024./1024.) << "Gi ";
                cout << "addr: 0x" << (long)buffer << " ";
                cout << "str: " << &buffer[size-5] << "\n";

                // cleanup
                delete [] buffer;

                // double size and continue
                size *= 2;
                cnt++;
        }
        return 0;
}
4b9b3361

Ответ 1

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

Что происходит здесь: вы используете только 5 байт. Мой ZX81 с 1980-х годов может справиться с этим.

Ответ 2

MacOS X, как и почти каждая современная операционная система, использует "задержанное выделение" для памяти. Когда вы вызываете new, ОС фактически не выделяет какую-либо память. Он просто отмечает, что ваша программа хочет определенный объем памяти, и эта область памяти, которую вы хотите, начинается с определенного адреса. Память фактически назначается только тогда, когда ваша программа пытается ее использовать.

Кроме того, память выделяется в единицах, называемых "страницами". Я считаю, что MacOS X использует 4kb-страницы, поэтому, когда ваша программа записывает в конец буфера, ОС дает вам 4096 байт, сохраняя остальную часть буфера, как просто "ваша программа хочет эту память".

Что касается того, почему вы нажимаете лимит на 64 терабайта, это потому, что текущие процессоры x86-64 используют 48-битную адресацию. Это дает 256 ТБ адресного пространства, которое равномерно распределяется между операционной системой и вашей программой. Удвоение распределения 64 ТБ точно поместило бы в вашу программу 128 ТБ половину адресного пространства, за исключением того, что программа уже занимает немного.

Ответ 3

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

malloc использует системный вызов mmap(MAP_ANONYMOUS) для получения страниц из ОС. (Предполагая, что OS X работает как Linux, поскольку они оба являются ОС POSIX). Эти страницы все копируются на запись, сопоставленные с одной физической нулевой страницей. то есть все они считаются нулевыми с пропуском TLB (без ошибки страницы и без распределения физической памяти). страница 4kiB. (Я не упоминаю огромные страницы, потому что они здесь не актуальны).

Запись на любую из этих страниц вызывает ошибку софт-страницы для ядра для обработки копий-на-записи. Ядро выделяет обнуленную страницу физической памяти и перенастраивает эту виртуальную страницу на физическую страницу. При возврате от ошибки страницы хранилище повторно выполняется и выполняется на этот раз.

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

Если вы на самом деле загрязнили больше страниц, чем в системе, сменой RAM + swap, у ядра возникнет проблема, потому что слишком поздно для malloc вернуть NULL. Это называется "overcommit" , и некоторые ОС разрешают его по умолчанию, а другие - нет. В Linux он настраивается.


Как объясняет Марк, вы исчерпали пар на 64TiB, потому что текущие реализации x86-64 поддерживают только 48-битные виртуальные адреса. Верхние 16 бит должны быть копиями бит 47. (т.е. Адрес является только каноническим, если 64-битное значение является расширением знака низких 48 бит).

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