2014-10-19 3 views
0

Я работаю над очень большими наборами данных. Я пытаюсь выделить 16 ГБ в одном массивевыделение 16 ГБ в одном массиве, malloc терпит неудачу

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

Кто-нибудь знает, почему это происходит?

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

мой вызов:

int* array = (int*) malloc(sizeof(int)* 1000000000 * 4);

спасибо всем!

@ ScottChamberlain, @Sanhdrir: он терпит неудачу, потому что он не возвращает указатель NULL. Как вы могли заметить, этот массив представляет собой матрицу. прежде чем распределять его таким образом, я попытался выделить его указателем на указатели. это потребовало большего пространства в памяти (8 миллиардов байт больше), чтобы сохранить адрес каждого указателя. Таким образом, я убил свою программу, а теперь нет, но когда я пытаюсь получить доступ к некоторым адресам, я получаю ошибку сегментации.

Редактировать если я выделил 10 блоков из 160 миллионов (или даже больше), я не получаю никаких ошибок и выделена память. проблема заключается в распределении одного большого блока. теперь мой вопрос: есть ли способ преодолеть этот предел?

edit2 @Sanhadrin ваша гипотеза все правильно, за исключением того факта, что я использую gcc. Я сообщаю здесь содержимое/ргос/MemInfo/файл MemTotal: 198049828 kB MemFree: 113419800 kB Buffers: 153064 kB Cached: 5689680 kB SwapCached: 124780 kB Active: 73880720 kB Inactive: 8998084 kB Active(anon): 70843644 kB Inactive(anon): 6192548 kB Active(file): 3037076 kB Inactive(file): 2805536 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 201273340 kB SwapFree: 164734524 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 76915376 kB Mapped: 16376 kB Shmem: 72 kB Slab: 190352 kB SReclaimable: 124660 kB SUnreclaim: 65692 kB KernelStack: 3432 kB PageTables: 259828 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 300298252 kB Committed_AS: 160461824 kB VmallocTotal: 34359738367 kB VmallocUsed: 733424 kB VmallocChunk: 34258351392 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 195520 kB DirectMap2M: 37507072 kB DirectMap1G: 163577856 kB

+0

, язык программирования c/C++ или другие? – SMA

+0

какой размер стека (ulimit -s)? – SMA

+1

Но ваше приложение само по себе 64-битное? В зависимости от платформы, компилятора и параметров вы можете создать 32-разрядный исполняемый файл. Кроме того, на самом деле у вас есть 16 ГБ свободной адресной памяти? Вы сказали, что «malloc() терпит неудачу». Вы действительно проверяете, является ли результат malloc NULL и проверяет errno, чтобы увидеть причину сбоя? Или вы ожидали, что он рухнет? –

ответ

1

объем информации делает это трудно ответить точно, но мне кажется:

  • Вы находитесь на x86- 64 архитектура
  • вы можете быть запущен Linux
  • у вас есть по крайней мере 16 ГБ оперативной памяти, но неизвестно, есть ли у вас более 16 Гб свободного RAM
  • вы компиляции с GCC с параметрами, установленными для создания 64-битного двоичного
  • Ваши звонки на таНос() возвращают на первый взгляд действительный (не нулевой) указатель
  • индексирование в этой памяти может привести к ошибке сегментации

Если вы читаете страницу человека таНоса, он говорит:

Примечание

По умолчанию Linux следует оптимистической стратегии распределения памяти. Это означает, что когда malloc() возвращает не-NULL, нет гарантии, что память действительно доступна. В случае, если окажется, что система не в памяти, один или несколько процессов будут убиты убийцей OOM. Для получения дополнительной информации см. Описание/proc/sys/vm/overcommit_memory и/proc/sys/vm/oom_adj в proc (5) и исходный файл ядра Linux Documentation/vm/overcommit-accounting.

следит за чтением человек прока, он заявляет:

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

    0: heuristic overcommit (this is the default) 
       1: always overcommit, never check 
       2: always check, never overcommit 

      In mode 0, calls of mmap(2) with MAP_NORESERVE are not 
      checked, and the default check is very weak, leading to the 
      risk of getting a process "OOM-killed". Under Linux 2.4, any 
      nonzero value implies mode 1. 

Таким образом, в зависимости от настройки overcommit_memory, таНос() может возвращать правильный указатель, даже если запрашиваемое пространство не доступно, в надежде, что к тому времени, когда вы используете, что многое памяти, другие процессы будут прекращены, освободив необходимое пространство. Это не так, потому что вы используете его немедленно - это означает, что на самом деле у вас на самом деле нет 16 ГБ свободного места для работы. Далее:

  In mode 2 (available since Linux 2.6), the total virtual 
      address space that can be allocated (CommitLimit in 
      /proc/meminfo) is calculated as 
   CommitLimit = (total_RAM - total_huge_TLB) * 
          overcommit_ratio/100 + total_swap 

      where: 

       * total_RAM is the total amount of RAM on the system; 

       * total_huge_TLB is the amount of memory set aside for 
        huge pages; 

       * overcommit_ratio is the value in 
        /proc/sys/vm/overcommit_ratio; and 

       * total_swap is the amount of swap space. 

      For example, on a system with 16GB of physical RAM, 16GB of 
      swap, no space dedicated to huge pages, and an 
      overcommit_ratio of 50, this formula yields a CommitLimit of 
      24GB. 

      Since Linux 3.14, if the value in 
      /proc/sys/vm/overcommit_kbytes is nonzero, then CommitLimit is 
      instead calculated as: 

       CommitLimit = overcommit_kbytes + total_swap 

Так, по крайней мере, вы можете сделать лучшую работу по предотвращению его от overcommitting, так что таНос() терпит неудачу, как и ожидалось - но основная проблема в том, что вы просите о чрезвычайно большом количестве пространства, которое у вас, похоже, нет. Вы можете проверить/proc/meminfo, чтобы узнать, сколько на самом деле бесплатно в любой момент времени, и другую статистику памяти, чтобы узнать, в чем проблема и каковы ваши реальные пределы.

0

Если вам нужно выделить блоки памяти очень больших размеров, вы должны использовать службы своей операционной системы для сопоставления виртуальной памяти с процессом; не malloc().

Если у вас есть надежда на выделение 16 ГБ на вашей системе, вам необходимо сделать это таким образом.

Смежные вопросы