Часть приложения, я продолжаю работать, является простым находящимся в pthread сервером, который связывается по сокету TCP/IP. Я пишу это в C, потому что это будет выполнением в ограниченной среде памяти. Мой вопрос: что должна сделать программа, если один из потоков встречается с malloc (), который возвращает ПУСТОЙ УКАЗАТЕЛЬ? Возможности я придумал до сих пор:
Первая опция является, очевидно, самой легкой, но кажется очень неправильной. Второй также кажется неправильным, так как я не знаю точно, что произойдет. Третья опция кажется заманчивой за исключением двух проблем: во-первых, все потоки не должны быть соединены назад с основным потоком при нормальных обстоятельствах и во-вторых для завершения выполнения потока, большинство остающихся потоков должно будет назвать malloc () снова так или иначе.
Что я сделаю?
Это одна из причин, по которой жесткие системы space / rad обычно запрещают динамическое выделение памяти. Когда malloc ()
дает сбой, очень сложно «вылечить» сбой. У вас есть несколько вариантов:
malloc ()
(вообще или как обычно). Вы можете обернуть malloc () , чтобы выполнять дополнительную работу при сбоях, например, уведомлять что-то еще. Это полезно при использовании чего-то вроде сторожевого пса. Вы также можете использовать полноценный сборщик мусора , хотя я не рекомендую его. Лучше выявить и устранить утечки. malloc ()
, который не будет переоценивать его. Если вы тщательно профилировали использование кучи (с помощью такого инструмента, как Valgrind massif или аналогичного), вы можете разумно изменить размер пула. Однако большинство из этих предложений сводятся к тому, чтобы не доверять / использовать систему malloc ()
, если отказ не возможен.
В вашем случае, я думаю, лучшее, что вы можете сделать, это сделать убедиться, что сторожевой таймер будет уведомлен в случае сбоя malloc ()
, чтобы ваш процесс (или всю систему) можно перезапустить. Вы же не хотите, чтобы он выглядел «живым и работающим» в тупике.Это может быть так же просто, как просто отменить связь с файлом.
Вести очень подробные журналы. В каком файле / строке / функции произошел сбой?
Если malloc ()
не удается получить всего несколько КБ, это хороший признак того, что ваш процесс действительно не может продолжаться надежно в любом случае.Если ему не удастся захватить несколько сотен МБ, вы сможете восстановиться и продолжить работу. По этому признаку любое действие, которое вы предпринимаете, должно основываться на том, сколько памяти вы пытаетесь получить, и если вызовы для выделения гораздо меньшего размера по-прежнему будут успешными.
Единственное, чего вы никогда не должны делать, - это просто работать с NULL-указателями и дать им потерпеть крах. Это просто небрежно, не дает полезного журнала, где что-то пошло не так, и создает впечатление, что ваше программное обеспечение имеет низкое / нестабильное качество.
Это работает в ОС? Об этом свидетельствует использование pthreads. Вы знаете, что malloc () когда-либо вернет NULL? В некоторых системах (например, Linux) ошибка возникает в malloc () и обрабатывается ОС (путем остановки процесса) без возврата malloc ().
Я бы посоветовал вам выделить пул памяти при инициализации вашего приложения и выделить из него, а не использовать malloc () после инициализации. Это даст вам контроль над алгоритмом распределения памяти и поведением при исчерпании памяти. Если для пула недостаточно памяти, при инициализации будет единая точка отказа, прежде чем ваше приложение сможет запустить что-то, что не может завершить.
В системах реального времени и встроенных системах обычно используется «распределитель памяти с фиксированными блоками» . Если ваша ОС не предоставляет услуги, это можно реализовать, предварительно выделив блоки памяти и поместив их указатели в очередь. Чтобы выделить блок, вы берете указатель из очереди, а чтобы освободить его, вы помещаете его обратно в очередь. Когда очередь пуста, память исчерпана, и вы можете либо заблокировать и обработать ошибку, либо заблокировать и дождаться, пока другой поток не вернет некоторую память. Вы можете создать несколько пулов с блоками разного размера или даже создать пул для определенной цели с блоками точного размера, необходимого для этой цели.
По личному опыту могу сказать, что частота отказов malloc часто переоценивается. Например, в Linux обычное «решение» - это вариант 2, и вы не получите сбоя malloc. Процесс просто внезапно умирает. В более крупных системах приложение имеет тенденцию к смерти, потому что пользователь или сторожевой таймер убивает его, как только свопинг сделал его не отвечающим.
Это немного усложняет очистку, а также затрудняет выработку общего решения.
Есть четвертый вариант: освободить немного памяти (кеши всегда хорошие кандидаты) и повторить попытку.
Если вы не можете себе этого позволить, я бы выбрал вариант 2 (очевидно, запись в журнал или печать какого-либо сообщения об ошибке) ... Единственное беспокойство по поводу очистки будет заключаться в закрытии открытых сетевых подключений упорядоченным образом, чтобы клиенты знать, что приложение на другой стороне закрывается, а не обнаруживать неожиданную проблему с подключением.
Зависит от вашей архитектуры, я думаю.
Означает ли ошибка malloc()
, что только этот поток не может продолжить работу, или же весь процесс нарушается в этом случае?
Обычно, когда память действительно ограничена (т.е. в микропроцессорных средах), хорошей идеей является избегать ВСЕХ динамических распределений памяти, чтобы избежать проблем, подобных этой.
В варианте 2 нет ничего плохого. Вы не должны предполагать - exit ()
завершает процесс, что означает, что все нити оборваны, и все убрано.
Не забудьте попытаться записать, где произошло сбойное выделение.