C ++ Список объектов, бросающий код std :: bad_alloc - PullRequest
0 голосов
/ 12 декабря 2018

Я пишу следующую программу и получаю исключение std :: bad_alloc.

class A{
public:
    int arr[5000];

    A() {
        for ( int i = 0; i < 5000; i++ ) {
            arr[i] = 0;
        }
    }
};

int main() {
    int cnt=0;
    std::list<A*> mylist;
    A *aref= NULL;
    for(int i=0;i<160000;i++){
        aref = new A();
        mylist.push_back(aref);
    }
}

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

Я запускаю ту же программу на Java с -Xmx8000m, и она нормально завершается.Моя оперативная память составляет 16 ГБ (если это имеет значение)

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

std::list реализован в виде двусвязного списка с узлами, выделенными в куче.Сам объект std::list<A*> mylist имеет автоматическую продолжительность хранения, он имеет небольшой sizeof, но каждый элемент, добавляемый к нему с mylist.push_back(aref), будет выполнять выделение кучи в дополнение к new A, который вы делаете вручную.

0 голосов
/ 12 декабря 2018

Вы выделяете 160000 ваших A с 5000 int в них, обычно размером около 4 байтов, поэтому вы выделяете 160000 *5000* 4 байта и / 1024 = 3.125.000 кибиБайти / 1024 = 3,051,7578125 мегабайт, то есть около 3 ГБ, что близко к верхнему пределу, что может получить 32-разрядный процесс, и я предполагаю, что даже при запуске 64-разрядных окон вы скомпилировали его с настройками по умолчанию для x86, то естьон будет работать с 32-битным режимом совместимости в Windows.Добавьте накладные расходы ваших 160000 указателей, которые вы сохранили в самом неэффективном контейнере std, плюс накладные расходы на содержимое подкачки, плюс, вероятно, добавленное заполнение, и вы выйдете из памяти.

Чтобы вернуться кВаш первоначальный вопрос:

  1. Список помещается в «стопку», т. е. с автоматическим сроком хранения (более точный термин), что означает только данные его домохозяйства (например, указатель на первый элемент).и один к последнему и его размер), но не элементы / узлы, которые он содержит, и даже если он это сделал, он не содержит большой материал, т. е. ваши A s, а просто указывает на них A* s,которые, в свою очередь, как и в любом контейнере std, за исключением std::array, хранятся в куче, т. е. «длительность динамического хранения», но по размеру они ничто по сравнению с 5000-дюймовыми, на которые они указывают.Поскольку вы размещаете с новым, ваш A никогда не очищается до тех пор, пока вы не вызовете удаление.C ++ очень отличается от Java.И ваш Java-код, вероятно, работает как 64-битный процесс, который знает, что сделала виртуальная машина, поскольку он увидел, что вы не будете использовать их в будущем.

Так что, если вы хотите, чтобы ваши A были на "«стек», т. е. длительность автоматического хранения, вы можете использовать std::array<A,160000> (это гораздо лучшая версия A [160000]), но я держу пари, что у вас вылетит стек с такими размерами.(В большинстве операционных систем вы получаете около 2 МБ стека на поток, но это может быть намного меньше, и ваше дерево вызовов также нуждается в размещении)

Если вы хотите, чтобы ваши A находились в «куче», то есть сдинамическое время хранения, т.е. в списке, используйте std::list<A> вместо std::list<A*> и полностью удалите выражение new.Однако по нескольким причинам лучшим контейнером по умолчанию является std::vector<A>, который хранит их в одном большом куске «кучи» памяти.

Нет такого явного ограничения в стандарте C ++, согласно §3.7.4 ISO / IEC 14882: 2014, new либо получает запрашиваемую сумму или более , либо не работает,так что это зависит от времени выполнения, то есть от реализации, то есть от операционной системы и компилятора, но в целом вы можете получить столько, сколько даст операционная система, что, как я сказал, составляет около 3-4 ГБ для x86 / 32-битных процессов.В противном случае это может быть намного больше, или в случае встроенных приложений, очень меньше до 0 (без динамического выделения).
...