Мне кажется, что все, что можно сделать с помощью стека, можно сделать с помощью кучи, но не все, что можно сделать с помощью кучи, можно сделать с помощью стека. Это верно? Тогда для простоты, и даже если мы теряем немного производительности при определенных рабочих нагрузках, разве не может быть лучше просто использовать один стандарт (т. Е. Кучу)?
Подумайте о компромиссе между модульностью и производительностью. Я знаю, что это не лучший способ описать этот сценарий, но в целом кажется, что простота понимания и дизайна может быть лучшим вариантом, даже если есть потенциал для повышения производительности.
Ответы:
Кучи плохо работают при быстром распределении и освобождении памяти. Если вы хотите захватить много крошечных объемов памяти в течение ограниченного периода времени, куча не ваш лучший выбор. Стек, с его сверхпростым алгоритмом выделения / освобождения, естественным образом превосходит его (даже в большей степени, если он встроен в аппаратное обеспечение), поэтому люди используют его для таких вещей, как передача аргументов функциям и хранение локальных переменных - наиболее Важным недостатком является то, что он имеет ограниченное пространство, и поэтому держать большие объекты в нем или пытаться использовать его для долгоживущих объектов - плохие идеи.
Полное избавление от стека ради упрощения языка программирования - это неправильный способ IMO. Лучшим подходом было бы абстрагировать различия, позволить компилятору выяснить, какой тип хранилища использовать, в то время как программист собирает более высокие конструкции уровня, которые ближе к тому, что думают люди, и на самом деле, языки высокого уровня, такие как C #, Java, Python и т. д., делают именно это. Они предлагают почти идентичный синтаксис для объектов, выделенных в куче, и выделенных в стеке примитивов («ссылочные типы» и «типы значений» в .NET lingo), либо полностью прозрачные, либо с несколькими функциональными отличиями, которые вы должны понимать, чтобы использовать язык правильно (но на самом деле вам не нужно знать, как стек и куча работают внутри).
источник
Проще говоря, стек - это не маленькая производительность. Это в сотни или тысячи раз быстрее, чем куча. Кроме того, большинство современных машин имеют аппаратную поддержку стека (например, x86), и функциональность оборудования, например, для стека вызовов, не может быть удалена.
источник
нет
Площадь стека в C ++ невероятно быстрая по сравнению. Я не рискну, чтобы опытные разработчики C ++ были бы открыты для отключения этой функциональности.
С C ++ у вас есть выбор и контроль. Дизайнеры не были особенно склонны вводить функции, которые добавляли значительное время выполнения или пространство.
Осуществляя этот выбор
Если вы хотите создать библиотеку или программу, которая требует, чтобы каждый объект выделялся динамически, вы можете сделать это с помощью C ++. Он будет выполняться относительно медленно, но тогда вы сможете получить эту «модульность». Для остальных из нас модульность всегда является необязательной, вводите ее по мере необходимости, потому что оба требуются для хороших / быстрых реализаций.
альтернативы
Есть другие языки, которые требуют, чтобы хранилище для каждого объекта было создано в куче; это довольно медленно, так что это ставит под угрозу дизайн (программы реального мира) таким образом, что это хуже, чем необходимость изучать оба (IMO).
И то, и другое важно, и C ++ дает вам возможность эффективно использовать оба для каждого данного сценария. Сказав это, язык C ++ может быть не идеальным для вашего дизайна, если эти факторы в вашем OP важны для вас (например, чтение на языках более высокого уровня).
источник
На самом деле снижение производительности, вероятно, будет значительным!
Как уже отмечали другие, стеки являются чрезвычайно эффективной структурой для управления данными, которые подчиняются правилам LIFO (последним первым обслужен). Распределение / освобождение памяти в стеке обычно является просто изменением регистра в ЦП. Изменение регистра - почти всегда одна из самых быстрых операций, которые процессор может выполнить.
Куча обычно представляет собой довольно сложную структуру данных, и для выделения / освобождения памяти потребуется много инструкций, чтобы выполнить всю связанную бухгалтерию. Хуже того, в обычных реализациях каждый вызов для работы с кучей потенциально может привести к вызову операционной системы. Вызовы операционной системы занимают очень много времени! Программа обычно должна переключаться из режима пользователя в режим ядра, и всякий раз, когда это происходит, операционная система может решить, что у других программ есть более насущные потребности, и что вашей программе нужно будет ждать.
источник
Симула использовала кучу для всего. Помещение всего в кучу всегда вызывает еще один уровень косвенности для локальных переменных, и это оказывает дополнительное давление на сборщик мусора (вы должны принять во внимание, что сборщики мусора тогда действительно сосали). Отчасти поэтому Бьярне изобрел C ++.
источник
Стеки чрезвычайно эффективны для данных LIFO, таких как, например, метаданные, связанные с вызовами функций. Стек также использует присущие конструктивные особенности процессора. Поскольку производительность на этом уровне имеет основополагающее значение практически для всего остального в процессе, принятие этого «маленького» попадания на этом уровне будет распространяться очень широко. Кроме того, куча памяти перемещается ОС, что может быть смертельно для стеков. Хотя стек может быть реализован в куче, он требует дополнительных затрат, которые затронут буквально каждый фрагмент процесса на самом гранулярном уровне.
источник
«эффективный» с точки зрения написания кода, может быть, но, безусловно, не с точки зрения эффективности вашего программного обеспечения. Распределение стека по существу бесплатное (для перемещения указателя стека и резервирования места в стеке для локальных переменных требуется всего несколько машинных инструкций).
Поскольку выделение стека почти не занимает времени, выделение даже в очень эффективной куче будет в 100 тысяч раз (если не более 1 миллиона раз) медленнее.
Теперь представьте, сколько локальных переменных и других структур данных использует типичное приложение. Каждое маленькое «я», которое вы используете в качестве счетчика цикла, выделяется в миллион раз медленнее.
Конечно, если оборудование достаточно быстрое, вы можете написать приложение, которое использует только кучу. Но теперь представьте себе, какое приложение вы могли бы написать, если бы использовали кучу и использовали то же оборудование.
источник
Возможно, вас заинтересует «Сборка мусора - это быстро, а стек - быстрее».
http://dspace.mit.edu/bitstream/handle/1721.1/6622/AIM-1462.ps.Z
Если я правильно прочитал, эти парни модифицировали компилятор C для выделения «кадров стека» в куче, а затем использовали сборку мусора для перераспределения кадров вместо выталкивания стека.
Выделенные стеком «кадры стека» решительно превосходят выделенные в куче «кадры стека».
источник
Как стек вызовов будет работать в куче? По сути, вы должны были бы выделить стек в куче в каждой программе, так почему бы не сделать это для OS +?
Если вы хотите, чтобы все было действительно просто и эффективно, просто предоставьте пользователю его кусок памяти и дайте ему разобраться с этим. Конечно, никто не хочет реализовывать все самостоятельно и поэтому у нас есть стек и куча.
источник
Требуются как стек, так и куча. Они используются в разных ситуациях, например:
По сути, механизмы нельзя сравнивать вообще, потому что многие детали различны. Единственное, что у них общего, так это то, что они оба так или иначе обращаются с памятью.
источник
Современные компьютеры имеют несколько уровней кэш-памяти в дополнение к большой, но медленной системе основной памяти. Можно сделать десятки обращений к самой быстрой кэш-памяти за время, необходимое для чтения или записи одного байта из системы основной памяти. Таким образом, доступ к одному местоположению в тысячу раз намного быстрее, чем доступ к 1000 (или даже 100) независимым местоположениям по одному. Поскольку большинство приложений многократно выделяют и освобождают небольшие объемы памяти вблизи вершины стека, места на вершине стека используются и используются повторно в огромном количестве, так что подавляющее большинство (более 99% в типичном приложении) доступ к стеку может быть обработан с использованием кеш-памяти.
В противоположность этому, если бы приложение неоднократно создавало и оставляло объекты кучи для хранения информации о продолжении, каждая версия каждого стекового объекта, который когда-либо создавался, должна была бы быть записана в основную память. Даже если к тому времени подавляющее большинство таких объектов станет бесполезным, когда ЦП захочет переработать страницы кеша, с которых они начали, ЦП не будет знать об этом. Следовательно, ЦП пришлось бы тратить много времени на медленную запись в память бесполезной информации. Не совсем рецепт скорости.
Еще одна вещь, которую следует учитывать, это то, что во многих случаях полезно знать, что ссылка на объект, переданная подпрограмме, не будет использоваться после выхода из подпрограммы. Если параметры и локальные переменные передаются через стек, и если проверка кода подпрограммы показывает, что она не сохраняет копию переданной ссылки, то код, вызывающий подпрограмму, может быть уверен, что если нет внешней ссылки на объект существовал до вызова, ни один не будет существовать после. В отличие от этого, если параметры передавались через объекты кучи, такие понятия, как «после возврата подпрограммы», становятся несколько более туманными, поскольку, если код сохранил копию продолжения, подпрограмма могла бы «возвращать» более одного раза после одиночный звонок.
источник