Не должен ли этот код вылетать - PullRequest
6 голосов
/ 25 октября 2010
int *p;
while(true)
{
 p = new int;
}

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

Почему это так?

Ответы [ 6 ]

9 голосов
/ 25 октября 2010

Похоже, вы не закроете этот вопрос, пока не увидите сбой:)

В Unix-подобных операционных системах вы можете ограничить объем виртуальной памяти, доступной процессу, используя команда ulimit .Установив ВМ на 1 МБ, я смог увидеть желаемые результаты примерно за 5 секунд:

$ ulimit -v $((1024*1024)) # set max VM available to process to 1 MB

$ ulimit -v                # check it.
1048576

$ time ./a.out             # time your executable.
terminate called after throwing an instance of 'St9bad_alloc'
  what():  std::bad_alloc
Aborted

real    0m5.502s
user    0m4.240s
sys  0m1.108s
9 голосов
/ 25 октября 2010

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

int *p;
while (true) { 
  p = new int[1024*1024*1024];
}

Хотя мой ответ основан на вашей кодовой базе с использованием стандартного распределителя STL, который генерирует ошибочное распределение памяти. Существуют другие доступные распределители, которые просто возвращают NULL при неудачном выделении. Этот тип распределителя никогда не завершится сбоем в этом коде, поскольку неудачное размещение не считается фатальным. Вам необходимо проверить возврат выделения для NULL, чтобы обнаружить ошибку.

Еще одно предупреждение: если вы работаете в 64-битной системе, сбой может занять значительно больше времени из-за увеличенного размера адресного пространства. Вместо телефонного опроса, проводимого по улице, это по всей стране.

7 голосов
/ 25 октября 2010

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

Попробуйте выделить больше памяти сразу:

int *p;
while(true)
{
 p = new int[1024*1024];
}
4 голосов
/ 25 октября 2010

Вы не подождали достаточно.

[Если вы хотите посмотреть, как он продвигается, добавьте вывод на каждые 1000000 циклов или что-то в этом роде. Это потерпит неудачу в конце концов.]

1 голос
/ 03 ноября 2010

Другая возможность: большинство ОС будут выполнять оптимистичное распределение.Когда вы используете malloc, скажем, 500 МБ, эта память может быть фактически не зарезервирована до тех пор, пока ваша программа на самом деле не попытается выполнить чтение или запись в нее.

В частности, Linux известен своей чрезмерной перспективой памяти, а затем полагается на OOM(нехватка памяти) убивает процессы, пытающиеся собрать данные по обещаниям ядра.

1 голос
/ 03 ноября 2010

Я думаю, что компилятор выполняет некоторую оптимизацию и на самом деле не выделяет память.Я запускал приведенные выше примеры (используя valgrind) несколько раз и видел, что, хотя там, где выделения, все где 0 байтов памяти.

Попробуйте это, и ваша программа будет убита (по крайней мере, в Unix):

#include <cstdio>

int main() {

int *p;

while (true) {
        p = new int[1024*1024];
        p[0] = 0;
        printf("%p\n",p);
        for(unsigned j = 1; j < 1024*1024; j++) {
                p[j] = p[j-1] + 1;
        }
}

return 0;
}

Вы видите, что единственное отличие состоит в том, что я использую выделенную память.

Таким образом, это на самом деле не дает сбоя, потому что я предполагаю, что ОС предотвращает сбой процесса, просто убивая егоНе уверен на 100% в этом)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...