it-roy-ru.com

Что если 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 действителен для проверки выделения памяти?

20
sam32

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

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

27
Ernest Friedman-Hill

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

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

8
AnT

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

3
Richard J. Ross III

Без споров, почему или когда это было бы полезно, попытки перераспределения в цикле могут работать, по крайней мере, в 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 ГБ RAM и ​​системным файлом подкачки я получаю следующий вывод (собранный с 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 ГБ).

2
0kcats

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

0
tbert

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

0
wuampa

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

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

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

0
askmish