Что делать, если 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 действительным для проверки распределения памяти?
Ответы
Ответ 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 (программа может застрять там навсегда), попробуйте освободить некоторую память, удерживаемую каким-либо другим процессом или потоком, если вы можете и затем повторить попытку.
Другой альтернативой могло бы стать увеличение памяти за счет увеличения файла подкачки или памяти подкачки, на лету, из самого кода (но его опасного и не предпочтительного) или сделать это вручную.
Лучший способ избежать таких проблем - рассчитать или оценить потребность в памяти, при написании самого кода.