Ну, я знаю, что есть такие вещи, как malloc / free для C и new / using-a-destructor для управления памятью в C ++, но мне было интересно, почему нет «новых обновлений» для этих языков, которые позволяют пользователю есть возможность вручную управлять памятью, или чтобы система делала это автоматически (сборка мусора)?
Что-то вроде вопроса новичка, но был в CS только около года.
garbage-collection
Dark Templar
источник
источник
Ответы:
Сбор мусора требует структур данных для отслеживания распределения и / или подсчета ссылок. Это создает дополнительные затраты памяти, производительности и сложности языка. C ++ спроектирован так, чтобы быть «близким к металлу», другими словами, он использует более высокую производительность в сравнении с функциями удобства. Другие языки делают этот компромисс по-другому. Это одно из соображений при выборе языка, какой акцент вы предпочитаете.
Тем не менее, существует множество схем подсчета ссылок в C ++, которые достаточно легки и производительны, но они есть в библиотеках, как коммерческих, так и с открытым исходным кодом, а не частью самого языка. Подсчет ссылок для управления временем жизни объекта - это не то же самое, что сбор мусора, но он решает многие из тех же проблем и лучше подходит для базового подхода C ++.
источник
Строго говоря, на языке Си вообще нет управления памятью. malloc () и free () - это не ключевые слова в языке, а просто функции, которые вызываются из библиотеки. Это различие может быть педантичным сейчас, потому что malloc () и free () являются частью стандартной библиотеки C и будут предоставлены любой стандартной реализацией C, но это не всегда было верно в прошлом.
Зачем вам язык без стандарта для управления памятью? Это восходит к происхождению C как «портативная сборка». Существует множество случаев использования аппаратных средств и алгоритмов, которые могут извлечь выгоду или даже потребовать специализированных методов управления памятью. Насколько я знаю, нет способа полностью отключить встроенное управление памятью Java и заменить его своим. Это просто неприемлемо в некоторых ситуациях с высокой производительностью / минимальными ресурсами. C обеспечивает почти полную гибкость, чтобы точно выбрать, какую инфраструктуру будет использовать ваша программа. Заплаченная цена состоит в том, что язык C очень мало помогает в написании правильного кода без ошибок.
источник
malloc()
илиfree()
. (например, MLAP-компиляторы для PIC)Реальный ответ заключается в том, что единственный способ создать безопасный и эффективный механизм сборки мусора - это поддержка непрозрачных ссылок на уровне языка. (Или, наоборот, отсутствие поддержки уровня языка для прямого манипулирования памятью.)
Java и C # могут сделать это, потому что у них есть специальные ссылочные типы, которыми нельзя манипулировать. Это дает среде выполнения свободу делать такие вещи, как перемещение выделенных объектов в памяти , что имеет решающее значение для высокопроизводительной реализации GC.
К сведению, ни одна современная реализация GC не использует подсчет ссылок , так что это полностью красная сельдь. Современные GC используют коллекцию поколений, где новые выделения обрабатываются, по существу, так же, как выделения стека в языке, подобном C ++, и затем периодически все вновь выделенные объекты, которые еще живы, перемещаются в отдельное пространство «оставшихся в живых», и все поколение объектов освобождается сразу.
У этого подхода есть свои плюсы и минусы: положительным моментом является то, что выделение кучи в языке, поддерживающем GC, происходит так же быстро, как и выделение стека в языке, не поддерживающем GC, и недостатком является то, что объекты, которые должны выполнить очистку перед уничтожением либо требуется отдельный механизм (например,
using
ключевое слово C # ), иначе их код очистки выполняется недетерминированно.Обратите внимание, что одним из ключей к высокопроизводительному GC является то, что должна быть языковая поддержка для специального класса ссылок. C не имеет этой языковой поддержки и никогда не будет; поскольку C ++ имеет перегрузку операторов, он может эмулировать тип указателя GC, хотя это должно быть сделано осторожно. Фактически, когда Microsoft изобрела свой диалект C ++, который будет работать под CLR (среда выполнения .NET), им пришлось изобрести новый синтаксис для «ссылок на стиль C #» (например
Foo^
), чтобы отличать их от «ссылок на стиль C ++». (напримерFoo&
).Что есть в C ++, и что регулярно используют программисты на C ++, так это умные указатели , которые на самом деле представляют собой просто механизм подсчета ссылок. Я бы не считал подсчет ссылок «истинным» ГХ, но он дает многие из тех же преимуществ за счет более низкой производительности, чем ручное управление памятью или настоящий ГХ, но с преимуществом детерминированного уничтожения.
В конце концов, ответ на самом деле сводится к особенностям дизайна языка. C сделал один выбор, C ++ сделал выбор, который позволил ему быть обратно совместимым с C, в то же время предоставляя альтернативы, которые достаточно хороши для большинства целей, а Java и C # сделали другой выбор, который несовместим с C, но также достаточно хорош для большинство целей. К сожалению, серебряной пули не существует, но знание различных вариантов поможет вам выбрать правильный вариант для любой программы, которую вы сейчас пытаетесь построить.
источник
std::unique_ptr
это «языковая поддержка непрозрачных ссылок»? (Это была не та поддержка, которую я имел в виду, и я также не думаю, что этого достаточно, если поддержка прямого манипулирования памятью не была также удалена из C ++.) Я упоминаю умные указатели в своем ответе, и я бы рассмотрелstd:unique_ptr
умный указатель поскольку он действительно выполняет подсчет ссылок, он поддерживает только особые случаи, когда количество ссылок равно нулю или единице (иstd::move
является механизмом обновления счетчика ссылок).std::unique_ptr
не имеет счетчика ссылок и неstd::move
имеет никакого отношения к ссылкам вообще (таким образом, "нет" снижения производительности). Хотя я понимаю вашу точку зрения, так как уstd::shared_ptr
нее есть счетчик ссылок, который является бездействием, обновленнымstd::move
:)malloc
иfree
. Так что да, сборщик мусора может быть значительно быстрее. (Обратите внимание, что я сказал «может быть» - конечно, на точную производительность каждой программы влияет множество факторов.)Потому что при использовании возможностей C ++ в этом нет необходимости.
Херб Саттер: « Я не писал удалить годами ».
см. Написание современного кода на C ++: как C ++ развивался на протяжении многих лет 21:10
Это может удивить многих опытных программистов на C ++.
источник
«Все» сборщик мусора - это процесс, который периодически запускается для проверки наличия в памяти объектов, на которые нет ссылок, и их удаления. (Да, я знаю, что это грубое упрощение). Это не свойство языка, а рамки.
Есть сборщики мусора , написанные для C и C ++ - это одно , например.
Одна из причин, по которой никто не был «добавлен» к языку, может быть из-за огромного объема существующего кода, который никогда не будет использовать его, поскольку они используют свой собственный код для управления памятью. Другая причина может заключаться в том, что типам приложений, написанных на C и C ++, не нужны служебные данные, связанные с процессом сборки мусора.
источник
malloc
иfree
, вы нарушите правильную программу.free
пока не покончу с этим. Но предлагаемый вами сборщик мусора, который не освобождает память до тех пор, пока я явно не вызову,free
вовсе не сборщик мусора.C был разработан в эпоху, когда сборка мусора была едва ли возможной. Он также был предназначен для использования там, где сборка мусора обычно не работает - «голое железо», среды реального времени с минимальным объемом памяти и минимальной поддержкой времени выполнения. Помните, что C был языком реализации для первого Unix, который работал на pdp-11 с 64 * K * байтами памяти. Изначально C ++ был расширением C - выбор уже был сделан, и очень сложно перенести сборку мусора на существующий язык. Это то, что нужно встроить с первого этажа.
источник
У меня нет точных цитат, но Бьярне и Херб Саттер говорят что-то вроде:
В современном C ++ вы используете умные указатели и поэтому не имеете мусора.
источник
Вы спрашиваете, почему эти языки не были обновлены, чтобы включить дополнительный сборщик мусора.
Проблема с необязательной сборкой мусора заключается в том, что вы не можете смешивать код, который использует разные модели. То есть, если я напишу код, предполагающий, что вы используете сборщик мусора, вы не сможете использовать его в своей программе, для которой сборка мусора отключена. Если вы это сделаете, он будет протекать везде.
источник
Можете ли вы представить написание обработчика устройства на языке с сборкой мусора? Сколько битов может прийти по линии во время работы GC?
Или операционная система? Как вы можете запустить сборку мусора еще до того, как запустите ядро?
C предназначен для низкого уровня, близкого к аппаратным задачам. Проблема? Это настолько хороший язык, что это хороший выбор для многих задач более высокого уровня. Языковые цари знают об этом использовании, но они должны поддерживать требования драйверов устройств, встроенного кода и операционных систем в качестве приоритета.
источник
Короткий и скучный ответ на этот вопрос заключается в том, что для людей, которые пишут сборщики мусора, должен существовать язык без сбора мусора. Концептуально нелегко иметь язык, который в то же время обеспечивает очень точное управление макетом памяти и имеет GC, работающий на вершине.
Другой вопрос, почему в C и C ++ нет сборщиков мусора. Ну, я знаю, что в C ++ есть пара таких, но они не очень популярны, потому что они вынуждены иметь дело с языком, который изначально не был предназначен для GC, и людьми, которые все еще используют C ++ в этот возраст на самом деле не тот, который пропускает GC.
Кроме того, вместо добавления GC к старому языку, не относящемуся к GC, на самом деле проще создать новый язык, который имеет почти такой же синтаксис при поддержке GC. Java и C # являются хорошими примерами этого.
источник
Есть различные проблемы, в том числе ...
delete
илиfree
явно. Подход GC по-прежнему имеет преимущество - нет висячих ссылок - и статический анализ может выявить некоторые случаи, но, опять же, нет единого идеального решения для всех случаев.По сути, отчасти это касается возраста языков, но в любом случае всегда найдется место для языков, не относящихся к GC, даже если это немного нишевое место. А если серьезно, в C ++ отсутствие GC не имеет большого значения - ваша память управляется по-другому, но она не является неуправляемой.
Управляемый Microsoft C ++ имеет, по крайней мере, некоторую способность смешивать GC и не-GC в одном приложении, что позволяет сочетать преимущества каждого из них, но у меня нет опыта, чтобы сказать, насколько хорошо это работает на практике.
Rep-whoring ссылки на похожие ответы моих ...
источник
Сборка мусора принципиально несовместима с системным языком, используемым для разработки драйверов для оборудования с поддержкой DMA.
Вполне возможно, что единственный указатель на объект будет сохранен в аппаратном регистре на некотором периферийном устройстве. Поскольку сборщик мусора не узнает об этом, он подумает, что объект недоступен, и соберет его.
Этот аргумент имеет двойное значение для сжатия GC. Даже если вы будете осторожны, сохраняя в памяти ссылки на объекты, используемые периферийными устройствами, когда GC переместит объект, он не будет знать, как обновить указатель, содержащийся в регистре конфигурации периферийных устройств.
Так что теперь вам нужно сочетание неподвижных буферов DMA и объектов, управляемых GC, что означает, что у вас есть все недостатки обоих.
источник
Потому что C & C ++ - это языки относительно низкого уровня, предназначенные для общего назначения, даже, например, для запуска на 16-разрядном процессоре с 1 МБ памяти во встроенной системе, которая не может позволить себе тратить память на gc.
источник
В C ++ и C. есть сборщики мусора. Не знаю, как это работает в C, но в C ++ вы можете использовать RTTI для динамического обнаружения графа объектов и использования его для сборки мусора.
Насколько мне известно, вы не можете написать Java без сборщика мусора. Небольшой поиск обнаружил это .
Ключевое различие между Java и C / C ++ заключается в том, что в C / C ++ выбор всегда остается за вами, тогда как в Java вы часто оставлены без вариантов.
источник
Это компромисс между производительностью и безопасностью.
Нет никаких гарантий, что ваш мусор будет собираться в Java, поэтому он может зависать, занимая много места, в то время как сканирование не связанных объектов (например, мусора) также занимает больше времени, чем явное удаление или освобождение неиспользуемого объекта.
Преимущество, конечно, в том, что можно создавать язык без указателей или без утечек памяти, поэтому вы с большей вероятностью создадите правильный код.
Иногда в этих дебатах может быть небольшое «религиозное» преимущество - будьте осторожны!
источник
Вот список присущих GC проблем, которые делают его непригодным для использования на системном языке, таком как C:
GC должен работать ниже уровня кода, объектами которого он управляет. Такого уровня в ядре просто нет.
GC должен время от времени останавливать управляемый код. Теперь подумайте о том, что произойдет, если это произойдет с вашим ядром. Вся обработка на вашем компьютере остановится, скажем, на миллисекунду, в то время как GC сканирует все существующие выделения памяти. Это убило бы все попытки создать системы, работающие в соответствии со строгими требованиями в реальном времени.
GC должен уметь различать указатели и не указатели. То есть он должен иметь возможность просматривать каждый существующий объект памяти и создавать список смещений, в которых можно найти его указатели.
Это открытие должно быть совершенным: GC должен быть в состоянии преследовать все указатели, которые он обнаруживает. Если он разыменовывает ложный положительный результат, он, скорее всего, потерпит крах. Если ему не удалось обнаружить ложноотрицательный результат, он, скорее всего, уничтожит объект, который все еще используется, сбой управляемого кода или молчаливое повреждение его данных.
Для этого абсолютно необходимо, чтобы информация о типе хранилась в каждом существующем объекте. Однако и C, и C ++ допускают простые старые объекты данных, которые не содержат информации о типе.
GC по своей сути медленный бизнес. Программисты, которые были общены с Java, могут не осознавать этого, но программы могут быть на порядок быстрее, если они не реализованы в Java. И одним из факторов, которые делают Java медленным, является GC. Это то, что исключает использование в суперкомпьютерах языков GCed, таких как Java. Если энергопотребление вашей машины составляет миллион в год, вы не хотите платить даже 10% от этого за сборку мусора.
C и C ++ - это языки, созданные для поддержки всех возможных вариантов использования. И, как вы видите, многие из этих вариантов использования исключаются сборкой мусора. Таким образом, для поддержки этих вариантов использования C / C ++ не может быть сборщиком мусора.
источник