Я могу записать приложение C, не используя "кучу"?

Старый вопрос, но, похоже, проблема возникает часто при работе Android Studio 1.1.0. Это часто происходит после того, как я очищаю все существующие журналы.

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

10
задан Community 23 May 2017 в 10:29
поделиться

11 ответов

Однажды я сделал это во встроенной среде, где мы писали «сверхбезопасный» код для биомедицинских машин. Malloc () были явно запрещены, частично из-за ограничений ресурсов и из-за неожиданного поведения, которое вы можете получить от динамической памяти (ищите malloc (), VxWorks / Tornado и фрагментацию, и вы получите хороший пример).

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

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

28
ответ дан 3 December 2019 в 13:22
поделиться

Как ни странно, однажды я видел приложение базы данных, которое полностью полагалось на статическую выделенную память. У этого приложения были строгие ограничения на длину поля и записи. Даже встроенный текстовый редактор (я все еще дрожу, называя его так) не мог создавать тексты, содержащие более 250 строк текста. Это решило вопрос, который у меня возник в то время: почему для каждого клиента разрешено только 40 записей?

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

Вы можете выделить динамическую память в стеке, используя вызовы библиотеки alloca ().

8
ответ дан 3 December 2019 в 13:22
поделиться

Вы можете использовать функцию alloca () , которая выделяет память в стеке - эта память будет автоматически освобождена при выходе из функции. alloca () зависит от GNU, вы используете GCC, поэтому он должен быть доступен.

См. man alloca .

Другой вариант - использовать массивы переменной длины, но вам необходимо использовать режим C99.

5
ответ дан 3 December 2019 в 13:22
поделиться

1: Да, можете - если вам не нужно динамическое распределение памяти, но оно может иметь ужасную производительность в зависимости от вашего приложения. (т. е. отказ от кучи не даст вам более качественных приложений)

2: Нет, я не думаю, что вы можете динамически выделять память в стеке, поскольку эта часть управляется компилятором.

2
ответ дан 3 December 2019 в 13:22
поделиться

Можно выделить большой объем памяти из стека в main () и позже выделить его в коде. Это глупо, поскольку это означает, что ваша программа занимает память, которая ей на самом деле не нужна.

Я не могу придумать никаких причин (за исключением какой-то глупой задачи по программированию или учебного упражнения) для желания избежать кучи . Если вы «слышали», что выделение кучи происходит медленно, а выделение стека происходит быстро, то это просто потому, что куча включает динамическое выделение . Если бы вы динамически выделяли память из зарезервированного блока в стеке, это было бы так же медленно.

Выделение стека выполняется легко и быстро, потому что вы можете освободить только «самый молодой» элемент в стеке. Он работает для локальных переменных. Это не t работают для динамических структур данных.

Изменить: Увидев мотивацию вопроса ...

Во-первых, куча и стек должны конкурировать за одинаковое количество доступного пространства. Как правило, они растут друг к другу. Это означает, что если вы каким-то образом переместите все свое использование кучи в стек, то вместо того, чтобы стек сталкиваться с кучей, размер стека просто превысит объем доступной вам оперативной памяти.

Я думаю, вам просто нужно следить за своей кучей и использование стека (вы можете захватить указатели на локальные переменные, чтобы получить представление о том, где сейчас находится стек), и, если он слишком высок, уменьшите его. Если у вас много небольших динамически выделяемых объектов, помните, что каждое выделение имеет некоторые накладные расходы на память, поэтому выделение их из пула может помочь сократить требования к памяти.

3
ответ дан 3 December 2019 в 13:22
поделиться

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

Например, вам нужно построить двоичное дерево неизвестного размера и ссылаться на него. Задайте макет записи, описывающий узел дерева, где указатели на другие узлы фактически являются номерами записей в вашем файле дерева. Напишите подпрограммы, которые позволяют добавлять к дереву, записывая дополнительную запись в файл, и обходить дерево, читая запись, находя ее дочерний элемент как другой номер записи, читая эту запись и т. Д.

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

2
ответ дан 3 December 2019 в 13:22
поделиться

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

Большая куча, которая будет выделена позже, все равно будет подвержена нехватке памяти и единственное, что нужно сделать, - это включить сторожевого пса (или аналогичное действие). Использование стека звучит привлекательно, но если вы собираетесь выделять в стеке большие буферы / структуры данных, вы должны быть уверены, что стек достаточно велик, чтобы обрабатывать все возможные пути кода, которые может выполнить ваша программа.

2
ответ дан 3 December 2019 в 13:22
поделиться

Меня больше всего беспокоит, действительно ли помогает отмена кучи?

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

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

Мои советы по решению этого случая:

  1. Рассчитайте общее потенциальное использование памяти вашей программой. Если он слишком близок к объему памяти, который вы подготовили для оборудования, но еще не превышает его, то вы можете
  2. Попытаться использовать меньше памяти (улучшить алгоритмы) или использовать память более эффективно (например, меньшего размера и более обычного размера. malloc () для уменьшения фрагментации кучи); или
  3. Просто купите больше памяти для оборудования.

Конечно, вы можете попробовать поместить все в заранее определенное пространство статической памяти, но очень вероятно, что на этот раз это будет перезапись стека в статическую память. Так что улучшите алгоритм, чтобы вначале он потреблял меньше памяти, а во вторую - покупайте больше памяти.

меньше и более обычного размера malloc () для уменьшения фрагментации кучи); или
  • Просто купите больше памяти для оборудования.
  • Конечно, вы можете попробовать поместить все в заранее определенное пространство статической памяти, но очень вероятно, что на этот раз это будет перезапись стека в статическую память. Так что улучшите алгоритм, чтобы вначале он потреблял меньше памяти, а во вторую - покупайте больше памяти.

    меньше и более обычного размера malloc () для уменьшения фрагментации кучи); или
  • Просто купите больше памяти для оборудования.
  • Конечно, вы можете попробовать поместить все в заранее определенное пространство статической памяти, но очень вероятно, что на этот раз это будет перезапись стека в статическую память. Так что улучшите алгоритм, чтобы вначале он потреблял меньше памяти, а во вторую - покупайте больше памяти.

    0
    ответ дан 3 December 2019 в 13:22
    поделиться

    Я бы решил эту проблему другим способом - если вы думаете, что стек и куча конфликтуют, проверьте это, защитившись от этого.

    Например (в системе * ix) попробуйте mprotect () обработать последнюю страницу стека (при условии, что стек фиксированного размера), чтобы она была недоступна. Или - если ваш стек растет - тогда mmap страница в середине стека и кучи. Если вы получаете segv на своей странице защиты, вы знаете, что закончили конец стека или кучи; и, посмотрев на адрес ошибки сегмента, вы можете увидеть, какой из стека и кучи столкнулся.

    0
    ответ дан 3 December 2019 в 13:22
    поделиться

    Часто можно написать свое встроенное приложение без использования динамического распределения памяти. Во многих встроенных приложениях использование динамического выделения памяти не рекомендуется из-за проблем, которые могут возникнуть из-за фрагментации кучи. Со временем становится весьма вероятным, что не будет области свободного пространства в куче подходящего размера, позволяющей выделить память, и если не будет схемы для обработки этой ошибки, приложение выйдет из строя. Существуют различные схемы, позволяющие обойти это, одна из которых заключается в том, чтобы всегда выделять объекты фиксированного размера в куче, чтобы новое выделение всегда помещалось в освобожденную область памяти. Другой - для обнаружения сбоя выделения и выполнения процесса дефрагментации для всех объектов в куче (оставлено в качестве упражнения для читателя! )

    Вы не говорите, какой процессор или набор инструментов вы используете, но во многих случаях статика, куча и стек выделяются отдельным определенным сегментам в компоновщике. Если это так, значит, ваш стек должен расти за пределами пространства памяти, которое вы для него определили. Решение, которое вам нужно, - уменьшить размер кучи и / или статической переменной (при условии, что эти две смежные), чтобы для стека было больше. Можно уменьшить кучу в одностороннем порядке, хотя это может увеличить вероятность проблем фрагментации. Обеспечение отсутствия ненужных статических переменных освободит некоторое пространство за счет возможного увеличения использования стека, если переменная сделана автоматически.

    Если это так, значит, ваш стек должен расти за пределами пространства памяти, которое вы для него определили. Решение, которое вам нужно, - уменьшить размер кучи и / или статической переменной (при условии, что эти две смежные), чтобы для стека было больше. Можно уменьшить кучу в одностороннем порядке, хотя это может увеличить вероятность проблем фрагментации. Обеспечение отсутствия ненужных статических переменных освободит некоторое пространство за счет возможного увеличения использования стека, если переменная сделана автоматически.

    Если это так, значит, ваш стек должен расти за пределами пространства памяти, которое вы для него определили. Решение, которое вам нужно, - уменьшить размер кучи и / или статической переменной (при условии, что эти две смежные), чтобы для стека было больше. Можно уменьшить кучу в одностороннем порядке, хотя это может увеличить вероятность проблем фрагментации. Обеспечение отсутствия ненужных статических переменных освободит некоторое пространство за счет возможного увеличения использования стека, если переменная сделана автоматически.

    Можно уменьшить кучу в одностороннем порядке, хотя это может увеличить вероятность проблем фрагментации. Обеспечение отсутствия ненужных статических переменных освободит некоторое пространство за счет возможного увеличения использования стека, если переменная сделана автоматически.

    Можно уменьшить кучу в одностороннем порядке, хотя это может увеличить вероятность проблем фрагментации. Обеспечение отсутствия ненужных статических переменных освободит некоторое пространство за счет возможного увеличения использования стека, если переменная сделана автоматически.

    0
    ответ дан 3 December 2019 в 13:22
    поделиться

    Вы не можете выполнить динамическое распределение памяти в C без использования памяти кучи. Было бы довольно сложно написать реальное приложение без использования Heap. По крайней мере, я не могу придумать, как это сделать.

    Кстати, почему вы хотите избежать кучи? Что в этом плохого?

    2
    ответ дан 3 December 2019 в 13:22
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: