Невозможно выделить 2-4 ГБ ОЗУ с новым [] / C ++ / Linux / x86_64 - PullRequest
6 голосов
/ 17 мая 2011

Для этого простого теста, а также для linux с 4 ГБ или ОЗУ, 0 байт подкачки и ЦП в режиме x86_64, я не могу выделить более 1 ГБ массива.

Источник:

#include <cstdio>
int main()
{
 for(int i=0;i<33;i++) { 
  char*a=new char[1<<i];
  *a=1;
  delete[]a; 
  printf("%d\n",i);
  fflush(stdout);
 }
}

Пробег:

$ file test
test: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV)
$ ./test
...
24
25
26
27
28
29
30
terminate called after throwing an instance of 'std::bad_alloc'
  what():  St9bad_alloc
Aborted

Нет ограничения на память:

virtual memory          (kbytes, -v) unlimited
data seg size           (kbytes, -d) unlimited

Почему ошибка?

Glibc - 2.3.4, ядро ​​- 2.6.9

ОБНОВЛЕНИЕ: Компилятор gcc4.1

Спасибо! Тест определенно имеет ошибку, 1ull<<i дает мне до 31 (2 ГБ). Эта ошибка была непреднамеренной. Но настоящий провальный код -

 for(j=0;j<2;j++)
  for(i=0;i<25;i++)
   some_array[j][i] = new int[1<<24];

чтобы в реальном коде не было переполнения знака.

Размер целого 4 байта:

$ echo 'main(){return sizeof(int);}'| gcc -x c - && ./a.out; echo $?
4

каждый запрос будет для 1 << 24 * 4 = 1 << 26; требуется всего 2 * 25 * (1 << 26) 3355443200 байт + 50 * sizeof (указатель) для some_array + 50 * (размер новых [] служебных данных). </p>

Ответы [ 4 ]

14 голосов
/ 17 мая 2011

Голая константа в C - это int. Подписанный инт. Так что 1 << 31 -2147483648. так как 1<<31 = 0x10000000 = -2147483648

Попробуйте (size_t)1 << i

5 голосов
/ 17 мая 2011

РЕДАКТИРОВАТЬ: В других ответах я вижу, что проблема, скорее всего, связана с тем, что число, переданное new[], становится отрицательным.Я согласен с тем, что это, скорее всего, так, и я оставляю этот ответ только потому, что считаю, что он содержит информацию, которая может иметь отношение к некоторым подобным случаям, когда проблема не в том, чтобы позвонить по номеру new[] с отрицательным номером.


Первый вопрос, который приходит на ум, - достаточно ли у вас памяти.С оперативной памятью 4 ГБ и без подкачки общий объем памяти, который может быть выделен всем процессам и , составляет 4 ГБ.

Обратите внимание, что даже если для процесса было доступно более 1 ГБ памяти, malloc и free (которые называются снизу new[] и delete[], могут не вернуть память обратносистемы, и они могут фактически хранить каждый из полученных / освобожденных блоков, так что объем памяти вашей программы может достигать 2 ГБ (необходимо проверить это с помощью реализации malloc в вашем ядре, поскольку многие реализации даютназад большие блоки).

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

0 голосов
/ 01 февраля 2013

Хотя обычно верно, что на 64-битной машине у вас достаточно адресного пространства для выделения нескольких ГБ непрерывной виртуальной памяти, вы пытаетесь выделить ее с помощью new / malloc.Новые / malloc традиционно являются не запросами любой памяти , а определенной частью памяти, которая выделяется с помощью системного вызова {s,} brk , который в основном перемещает конецсегмент данных процесса.Я думаю, что вы должны выделить такой большой объем памяти, используя mmap , что оставляет ОС свободной для выбора любого адресного блока.

0 голосов
/ 27 мая 2011

Каковы значения /proc/sys/vm/overcommit_memory и /proc/sys/vm/overcommit_ratio в вашей системе? Если у вас отключена избыточная загрузка памяти, возможно, вы не сможете выделить всю память в вашей системе. С включенной функцией overcommit (установите /proc/sys/vm/overcommit_memory в 0), вы сможете распределять массивы практически неограниченного размера (конечно, 10 с ГБ) в 64-битной системе.

...