У меня есть функция main
для моего приложения, и я выделяю, например, пути к файлам конфигурации и т. д. В настоящее время я использую для них malloc
, но они никогда не освобождаются и всегда доступны для использования в течение всего времени существования приложения. Я даже никогда не освобождаю их, потому что ОС уже автоматически освобождает выделенную память, когда приложение завершает работу. На данный момент есть ли какая-либо причина не использовать alloca
вместо malloc, потому что программа завершается, когда main
возвращается, а alloca
память удаляется только после освобождения функции, в которой она была выделена. Таким образом, исходя из этой логики, память, выделенная в основной функции с помощью alloca
, освобождается только после завершения программы, что желательно. Верны ли эти утверждения и есть ли причина не использовать alloca
(alloca - плохая практика, поэтому, когда я сказал, что alloca означал alloca или создать VLA в main
) в main
для объекта, подобного "глобальному VLA", который существует до завершения программы?
Если мне нужен глобальный VLA, могу ли я использовать alloca() в основной функции?
Ответы (4)
Вы можете использовать alloca/VLA в main, но зачем?
Типичная причина их использования - если у вас есть некоторая чувствительная к производительности часть, которая вызывается много, и вы не хотите накладных расходов malloc/free. Для main ваши данные выделяются один раз в начале программы, поэтому накладные расходы на несколько вызовов malloc незначительны.
Еще одна причина не использовать alloca/VLA в основном состоит в том, что они занимают пространство стека, которое является очень ограниченным ресурсом по сравнению с пространством кучи.
Зависит от того, сколько памяти вам нужно. Если он достаточно мал (скажем, несколько сотен байт или около того), вы можете безопасно выполнять alloca
в main()
или использовать VLA.
Но тогда, если размеры этих массивов имеют известный верхний предел, который не очень велик, было бы даже лучше и безопаснее объявить их глобально с этим верхним пределом в качестве размера. Таким образом, вы не потребляете пространство стека, и вам не нужно malloc
, а затем обеспечивать успешное выделение. Кроме того, тому, кто читает, становится ясно, что эта часть памяти живет столько же, сколько и программа.
Если размеры могут быть сколь угодно большими, то лучше всего продолжать использовать malloc()
, как вы уже это делали. Кстати, даже если вы вызываете malloc()
в main()
и используете его на протяжении всего времени существования программы, по-прежнему считается хорошей практикой освобождать его перед выходом.
atexit
и поместить в него free(ThePtr)
?
- person user16217248; 28.06.2021
foo_init()
, то должна быть и соответствующая функция foo_cleanup()
. Вы можете использовать atexit
, но обычно в этом нет необходимости. Просто вызовите функцию очистки вручную.
- person Lundin; 28.06.2021
NSApplicationMain
не возвращается, и это то, что использует мое приложение, см. это
- person user16217248; 01.07.2021
Технически нет, потому что любая переменная, объявленная в функции, не будет глобальной. Но вы можете сделать что-то вроде этого:
char *buffer;
int main(void) {
char buf[size];
buffer = buf;
Это даст вам интерфейс для глобального доступа к буферу.
На данный момент есть ли причина не использовать alloca вместо malloc?
Это один вопрос, который обычно следует задавать наоборот. Есть ли причина использовать alloca
вместо malloc
? Подумайте об изменении, если у вас есть проблемы с производительностью, но если вы просто хотите избежать использования free
, я бы сказал, что это плохая причина.
Но я не вижу здесь смысла. Если у вас есть выделенный буфер, который вы хотите прожить с момента запуска программы до ее завершения, просто освободите его в конце основной функции.
int main(void) {
char *buf = malloc(size);
// Do work
free(buf);
}
Я написал длинный ответ о alloca
и VLA:s, который может быть вам полезен. Действительно ли мне нужен malloc?
VLA (как определено стандартом) и нестандартный alloca
предназначены для использования для выделения временных небольших массивов в локальной области. Ничего больше.
Размещение больших объектов в стеке — известный источник незаметных и серьезных ошибок переполнения стека. По этой причине вам следует избегать больших объектов VLA и alloca
. Всякий раз, когда вам нужны большие объекты в области файла, они должны быть либо массивами static
, либо динамически распределяться с помощью malloc
.
Следует отметить, что выделение стека обычно происходит быстрее, чем выделение кучи, потому что выделение стека не должно касаться поиска, фрагментации и других проблем, связанных с реализацией кучи. Распределение стека просто говорит, что эти 100 байт принадлежат мне, и тогда вы готовы к работе.
Что касается общей путаницы между стеком и кучей, см. раздел Что выделяется в стеке и в куче?
Вы даже не можете поместить стандартный VLA в область файла, потому что размер массива должен быть целочисленным константным выражением. Плюс стандарт (C17 6.7.6) прямо говорит, что вам не разрешено:
Если идентификатор объявлен как объект со статической или потоковой продолжительностью хранения, он не должен иметь тип массива переменной длины.
Что касается alloca
, то это не стандартный C и по этой причине плохой. Но это также плохо, потому что у него нет безопасности типов, поэтому VLA предпочтительнее alloca
- он безопаснее и переносимее.
Следует отметить, что основная цель VLA в современном программировании, однако, состоит в том, чтобы включить указатели на VLA, а не выделять объекты массива типа VLA, что является функцией ограниченного использования.
Я даже никогда не освобождаю их, потому что ОС уже автоматически освобождает выделенную память, когда приложение завершает работу.
Хотя это правильно, по-прежнему считается хорошей практикой вызывать free() вручную. Потому что, если у вас где-то в программе есть какие-либо ошибки, связанные с повреждением кучи или указателями, вы получите сбой при вызове free(). Это хорошо, поскольку позволяет выявлять такие (распространенные) ошибки на ранних стадиях разработки.
(Если вас беспокоит производительность free(), вы можете исключить вызовы free() из сборки релиза и использовать их только в сборке отладки. Хотя производительность редко является проблемой при закрытии программы — обычно вы можете просто закрыть отключите графический интерфейс, если таковой имеется, а затем дайте программе проглотить очищающий код в фоновом режиме.)
alloca
нестандартен. иalloca
освобождается, когда текущий кадр стека умирает, т. е. когда возвращается функция, вызвавшаяalloca
. Вы всегда должныfree
своюmalloc
память, кстати. - person Raildex   schedule 28.06.2021main
? - person user16217248   schedule 28.06.2021main
, делает еще хуже использованиеalloca
, поскольку он будет постоянно использовать это драгоценное пространство стека. - person kaylum   schedule 28.06.2021