Исключение std::bad_alloc, хотя свободной памяти достаточно

Мой код работает под 64-битным Linux (openSUSE 13.1 x86_64), компилятор gcc (SUSE Linux) 4.8.1. В какой-то момент выполнения моей программы я получаю исключение std::bad_alloc, которое происходит от вызова std::vector push_back. Как видно из GDB:

(gdb) bt
#0  0x00007ffff6053849 in raise () from /lib64/libc.so.6
#1  0x00007ffff6054cd8 in abort () from /lib64/libc.so.6
#2  0x00007ffff694c655 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
#3  0x00007ffff694a7c6 in ?? () from /usr/lib64/libstdc++.so.6
#4  0x00007ffff694a7f3 in std::terminate() () from /usr/lib64/libstdc++.so.6
#5  0x00007ffff694aa1e in __cxa_throw () from /usr/lib64/libstdc++.so.6
#6  0x00007ffff694af1d in operator new(unsigned long) () from /usr/lib64/libstdc++.so.6
#7  0x0000000000457ca6 in allocate (__n=8388608, this=0x7ffffffe1f80)
    at /usr/include/c++/4.8/ext/new_allocator.h:104
#8  _M_allocate (__n=8388608, this=0x7ffffffe1f80) at /usr/include/c++/4.8/bits/stl_vector.h:168
#9  std::vector<std::pair<long, long>, std::allocator<std::pair<long, long> > >::_M_insert_aux (
    this=this@entry=0x7ffffffe1f80, __position=..., __x=...) at /usr/include/c++/4.8/bits/vector.tcc:345
#10 0x000000000045335c in push_back (__x=..., this=0x7ffffffe1f80) at /usr/include/c++/4.8/bits/stl_vector.h:913
#11 c_RoutingNetzwerk::LoescheAktuelleKnoten (this=this@entry=0x7ffffffe2f30,
    aktuelle_knoten=std::vector of length 12803276, capacity 16777216 = {...}, ebene=ebene@entry=0,
    aktueller_kantengrad=std::vector of length 17266677, capacity 17266677 = {...}, algo=...,
    neue_abgehende_kanten=std::vector of length 4194304, capacity 4194304 = {...},
    neue_eingehende_kanten=std::vector of length 4194304, capacity 4194304 = {...})
    at RoutingAlgorithmus/RoutingNetzwerk.cpp:3275

Вызов neue_abgehende_kanten.push_back(...) удваивает размер вектора, поэтому я пытаюсь выделить 4194304 * 2 * 16 байт = 128 МБ, и это не удается.

С другой стороны, у меня более чем достаточно памяти (всего 132 ГБ), и достаточно памяти (снимок сделан, когда моя программа прерывается в отладчике):

m2883:~ # free -m
             total       used       free     shared    buffers     cached
Mem:        129151     128582        568          0         59      56334
-/+ buffers/cache:      72189      56962
Swap:         8195          5       8190

Любые идеи, почему распределение не удается, тем не менее? Мне кажется, что система не освобождает свои кеши для использования моей программой?!


Я просто попробовал небольшой эксперимент и придумал

#include <cstdlib>
#include <stdio.h>

int main( int argc, char** argv)
{
    void* p = calloc( 1, 256 * 1024 * 1024 );
    if ( !p )
        printf( "failed\n" );
    else
        printf( "all done\n" );
}

Это все еще работает для 128 МБ, но не для 256 МБ.

А также:

m2883:~ # free -mh
             total       used       free     shared    buffers     cached
Mem:          126G       125G       593M         0B        60M        54G
-/+ buffers/cache:        70G        55G
Swap:         8.0G       5.4M       8.0G

transit@m2883:~/test> ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 1033140
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1033140
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Кажется, сервер каким-то образом неправильно настроен. Даже на недавно загруженной системе, на которой ничего не запущено, кроме нескольких системных служб, я не могу выделить больше, чем около 70 ГБайт, что я прочитал как 64 ГБ + 8 ГБ подкачки. Я связался с хостером сервера и пожаловался на ситуацию.

1 ответ

Без информации о вашем коде и конфигурации системы трудно точно знать.

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

Повторное выделение, освобождение и перераспределение могут легко привести к фрагментации памяти.

Превышение некоторой квоты также объясняет поведение.

Другие вопросы по тегам