Что делать, если malloc не удается? - программирование
Подтвердить что ты не робот

Что делать, если malloc не удается?

Если не удалось выполнить распределение malloc, попробуйте еще раз?

В чем-то вроде этого:

char* mystrdup(const char *s)  
{
    char *ab = NULL;

    while(ab == NULL) {
        ab=(char*)malloc(strlen(s)+1);  
    }

    strcpy(ab, s);
    return ab;
}

Является ли цикл while действительным для проверки распределения памяти?

4b9b3361

Ответ 1

В общем, современная реализация malloc() вернет NULL только как абсолютное последнее средство, и попытка снова определенно не поможет. Единственное, что поможет, это освободить память, а затем повторить попытку. Если ваше приложение хранит какие-либо расходные ресурсы, это будет время, чтобы освободить их, а затем дать ему еще один снимок.

В некоторых средах полезной практикой является выделение небольшого объема памяти в качестве фонда дождливого дня. Если malloc() когда-либо возвратит NULL, вы можете освободить этот фонд для дождливых дней, а затем выделить все ресурсы, необходимые для обработки ошибки, и выйти изящно. Это было обычной практикой при программировании со старым Macintosh Toolbox; если malloc() возвращен NULL, вы можете использовать это пространство для создания диалогового окна, чтобы сообщить о проблеме до выхода.

Ответ 2

В однопоточной программе "попытка снова", не освобождая память между попытками, не имеет практического смысла. Это будет просто цикл навсегда.

В многопоточной программе это может "работать", если другой поток, работающий параллельно, внезапно решает освободить часть своей собственной памяти. Петля в таком случае будет представлять собой классический цикл "занятого ожидания". Но даже в этом случае такой код имеет очень мало практического значения по нескольким причинам, чем один.

Ответ 3

Нет, никогда. Если malloc возвращает NULL, это указывает на ошибку, и вы должны, вероятно, отказаться.

Ответ 4

Не обсуждая, почему и когда это было бы полезно, попытки перераспределения в цикле могли бы работать, по крайней мере, в Windows с 64-битным кодом и настройках параметров по умолчанию. Более того, это может приобрести удивительно дополнительную дополнительную виртуальную память. Хотя, не делайте этого в бесконечном цикле, но вместо этого используйте конечное число попыток. В качестве доказательства попробуйте следующий код, который имитирует утечку 1 Мб памяти. Вы должны запустить его в сборке Release, желательно не под отладчиком.

for (int i = 0; i < 10; i++)
{
  size_t allocated = 0;
  while (1)
  {
    void* p = malloc(1024 * 1024);
    if (!p)
      break;

    allocated += 1;
  }

  //This prints only after malloc had failed.
  std::cout << "Allocated: " << allocated << " Mb\n";
  //Sleep(1000);
}

На моей машине с 8 ГБ ОЗУ и системным файлом подкачки я получаю следующий результат (построенный с VS2013 для целевой платформы x64, протестированный в Windows 7 Pro):

Allocated: 14075 Mb
Allocated: 16 Mb
Allocated: 2392 Mb
Allocated: 3 Mb
Allocated: 2791 Mb
Allocated: 16 Mb
Allocated: 3172 Mb
Allocated: 16 Mb
Allocated: 3651 Mb
Allocated: 15 Mb

Я не знаю точную причину такого поведения, но кажется, что отчисления начинают сбой после того, как изменение размера профайла не сможет идти в ногу с запросами. На моей машине файл подкачки вырос с 8 до 20 Гб после этого цикла (возвращается к 8 ГБ после выхода программы).

Ответ 5

Невероятно маловероятно, что это будет делать то, что вы хотите; если у вас нехватка памяти, занятость-петля, пока вы не получите больше, скорее всего, будет разочаровывать. Вы должны просто вернуть NULL в вызывающую программу, чтобы он мог справляться с исчерпанием ресурсов, либо освобождая память, которую больше не нужно, либо возвращая ошибку.

Ответ 6

malloc() пытается выделить память. Если это не удается, вместо повторной попытки выделить память в цикле while (программа может застрять там навсегда), попробуйте освободить некоторую память, удерживаемую каким-либо другим процессом или потоком, если вы можете и затем повторить попытку.

Другой альтернативой могло бы стать увеличение памяти за счет увеличения файла подкачки или памяти подкачки, на лету, из самого кода (но его опасного и не предпочтительного) или сделать это вручную.

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