Почему у С++ нет сборщика мусора?

Я не задаю этот вопрос из-за достоинства сборщика мусора в первую очередь. Моя основная причина для того, чтобы спросить об этом, так это то, что я знаю, что Bjarne Stroustrup сказал, что С++ будет иметь сборщик мусора в какой-то момент времени.

Сказав это, почему он не был добавлен? На С++ уже есть сборщики мусора. Это только одна из тех вещей, которые проще сказать, чем сделать? Или есть другие причины, по которым он не был добавлен (и не будет добавлен в С++ 11)?

Перекрестные ссылки:

Просто, чтобы уточнить, я понимаю причины, по которым у С++ не было сборщика мусора, когда оно было впервые создано. Мне интересно, почему сборщик не может быть добавлен.

Ответ 1

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

Цитата самого Бьярна Страустрапа:

Я надеялся, что сборщик мусора который может быть дополнительно включен будет частью С++ 0x, но были достаточно технических проблем, которые у меня есть делать только с подробным спецификация того, как такой сборщик интегрируется с остальной частью язык, если он предоставлен. Как и в случае с практически всеми функциями С++ 0x, существует экспериментальная реализация.

Существует хорошее обсуждение темы здесь.

Общий обзор:

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

С++ был построен с учетом конкурентов, у которого не было сбора мусора. Эффективность была главной проблемой, с которой С++ пришлось отбиваться от критики по сравнению с C и другими.

Существует 2 типа сбора мусора...

Явная сборка мусора:

С++ 0x будет иметь сбор мусора через указатели, созданные с помощью shared_ptr

Если вы этого хотите, вы можете использовать его, если вы этого не хотите, вы не вынуждены его использовать.

В настоящее время вы можете использовать boost: shared_ptr, если вы не хотите ждать С++ 0x.

Неявная сборка мусора:

У него нет прозрачной сборки мусора. Это будет фокус для будущих спецификаций С++.

Почему Tr1 не имеет неявной сборки мусора?

Есть много вещей, которые должны были иметь tr1 из С++ 0x, Бьярне Страуструп в предыдущих интервью заявил, что tr1 не имеет столько, сколько ему бы хотелось.

Ответ 2

Чтобы добавить к обсуждению здесь.

Известны проблемы с сборкой мусора, и понимание их помогает понять, почему в С++ нет никого.

1. Производительность?

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

В настоящее время широко используются 2 семейства GC:

  • Тип Mark-And-Sweep
  • Тип ссылочного счета

Mark And Sweep быстрее (меньше влияет на общую производительность), но он страдает от синдрома "замораживания мира": т.е. когда GC запускается, все остальное прекращается до тех пор, пока GC не очистится. Если вы хотите построить сервер, который отвечает за несколько миллисекунд... некоторые транзакции не оправдают ваших ожиданий:)

Проблема Reference Counting различна: подсчет ссылок добавляет служебные данные, особенно в средах с несколькими потоками, потому что вам нужно иметь атомный счет. Кроме того, существует проблема эталонных циклов, поэтому вам нужен умный алгоритм для обнаружения этих циклов и устранения их (как правило, "замораживание мира" тоже, хотя и менее частый). В общем, на сегодняшний день этот вид (хотя обычно более чувствительный или, скорее, замораживание реже) медленнее, чем Mark And Sweep.

Я видел работу разработчиков Eiffel, которые пытались реализовать сборщик мусора Reference Counting, который имел бы такую ​​же глобальную производительность до Mark And Sweep без аспекта "Замораживание мира". Для GC требовалось отдельную нить. Алгоритм был немного пугающим (в конце), но в документе была хорошая работа по введению понятий по одному и показ эволюции алгоритма от "простой" версии до полноценной. Рекомендуемое чтение, если только я могу вернуть руки в файл PDF...

2. Приобретение ресурсов - это инициализация

Это обычная идиома в C++, что вы обернете владение ресурсами внутри объекта, чтобы обеспечить их надлежащее освобождение. Он в основном используется для памяти, поскольку у нас нет сборки мусора, но он также полезен, тем не менее, для многих других ситуаций:

  • блокировки (многопоточный, дескриптор файла,...)
  • подключения (к базе данных, другому серверу,...)

Идея заключается в правильном управлении временем жизни объекта:

  • он должен быть живым до тех пор, пока вам это нужно
  • его следует убить, когда вы закончите с ним.

Проблема GC заключается в том, что если это помогает с первым и в конечном итоге гарантирует, что позже... этого "конечного" может быть недостаточно. Если вы отпустите блокировку, вам действительно понравится, что она будет выпущена сейчас, чтобы она не блокировала дальнейшие звонки!

Языки с GC имеют две проблемы:

  • не использовать GC при достаточном распределении стека: обычно это относится к проблемам производительности, но в нашем случае это действительно помогает, поскольку область определяет время жизни
  • using construct... но он явный (слабый) RAII, тогда как в С++ RAII неявный, так что пользователь НЕ МОЖЕТ НЕ НЕВОЗМОЖНО сделать ошибку (опустив ключевое слово using)

3. Умные указатели

Умные указатели часто отображаются в виде серебряной пули для обработки памяти в C++. Часто я слышал: в конце концов, нам не нужен GC, так как у нас есть умные указатели.

Нельзя быть более ошибочным.

Умные указатели помогают: auto_ptr и unique_ptr использовать концепции RAII, что очень полезно. Они настолько просты, что вы можете легко написать их самостоятельно.

Когда нужно обмениваться собственностью, тем не менее это становится сложнее: вы можете делиться между несколькими потоками, и есть несколько тонких проблем с обработкой счета. Поэтому естественно идет к shared_ptr.

Это здорово, что то, что Boost для всех, но это не серебряная пуля. На самом деле, главная проблема с shared_ptr заключается в том, что она эмулирует GC, реализованный с помощью Reference Counting, но вам нужно полностью реализовать обнаружение цикла... Urg

Конечно, есть эта weak_ptr штука, но я, к сожалению, уже видел утечки памяти, несмотря на использование shared_ptr из-за этих циклов... и когда вы находитесь в среде Multi Threaded, очень сложно обнаружить

4. Какое решение?

Нет серебряной пули, но, как всегда, это определенно возможно. В отсутствие GC необходимо четко понимать право собственности:

  • предпочитает иметь одного владельца за один раз, если возможно
  • Если нет, убедитесь, что диаграмма класса не имеет никакого цикла, относящегося к собственности, и разбивает их с помощью тонкого приложения weak_ptr

И действительно, было бы здорово иметь GC... однако нет тривиальной проблемы. И в то же время нам просто нужно свернуть рукава.

Ответ 3

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

C/С++ используется в слишком многих разных обстоятельствах. Я подозреваю, что что-то вроде boost smart-указателей будет достаточно для большинства пользователей.

Изменить. Автоматические сборщики мусора - это не столько проблема производительности (вы всегда можете купить больше серверов), это вопрос предикативной производительности.
Не зная, когда ГК собирается пинать, это похоже на использование нарколептического пилота авиакомпании, большую часть времени они замечательные, но когда вам действительно нужна отзывчивость!

Ответ 4

Одна из главных причин, по которой С++ не имеет встроенной сборки мусора, заключается в том, что сбор мусора для игры с деструкторами действительно очень тяжелый. Насколько я знаю, никто не знает, как его полностью решить. Есть много вопросов для решения:

  • детерминированные времена жизни объектов (подсчет ссылок дает вам это, но GC не делает. Хотя это может и не быть большой сделкой).
  • что произойдет, если деструктор выбрасывает, когда объект собирает мусор? Большинство языков игнорируют это исключение, так как на самом деле нет блока catch, чтобы его можно было переносить, но это, вероятно, не приемлемое решение для С++.
  • Как включить/отключить его? Естественно, это, скорее всего, решение для компиляции, но код, написанный для кода GC против кода, который написан для NOT GC, будет совсем другим и, вероятно, несовместимым. Как вы это согласовываете?

Это лишь некоторые из проблем.

Ответ 5

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

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

Общая идея сборки мусора заключается в том, что она должна сделать разумную попытку убедить, что распределение памяти будет успешным. К сожалению, практически невозможно гарантировать, что распределение памяти будет успешным, даже если у вас есть сборщик мусора. Это в какой-то мере верно, но особенно в случае С++, потому что (возможно) невозможно использовать копировальный коллектор (или что-то подобное), которое перемещает объекты в памяти в течение цикла сбора.

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

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

Тем не менее, это сильнее, чем было предложено для С++. предыдущее предложение [предупреждение: PDF] (который упал) ничего не гарантировал. В 28 страницах предложения, что вы получили на пути наблюдаемого извне поведения, была единственная (ненормативная) заметка, в которой говорилось:

[Примечание. Для программ, собранных для мусора, высококачественная хостинговая реализация должна пытаться максимизировать объем недостижимой памяти, которую он исправляет. -end note]

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

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

Я бы обобщил ситуацию математически: это сложная ситуация. Как знает любой математик, комплексное число имеет две части: реальную и мнимую. Мне кажется, что то, что мы имеем здесь, является реальными издержками, но преимуществами (по крайней мере в основном) мнимыми.

Ответ 6

Если вы хотите автоматическую сборку мусора, есть хорошие коммерческие сборщики мусора для публичного домена для С++. Для приложений, в которых сбор мусора подходит, С++ - превосходный сборник мусора, который отличается выгодным соотношением с другими языками, собранными с мусором. См. Язык программирования С++ (3-е издание) для обсуждения автоматической сборки мусора на С++. См. Также, Ханс-Дж. Сайт Boehm для сбора мусора C и С++. Кроме того, С++ поддерживает методы программирования, которые позволяют управлять памятью безопасно и неявно без сборщика мусора.

Источник: http://www.stroustrup.com/bs_faq.html#garbage-collection

Что касается того, почему он не встроен в него, если я правильно помню, он был изобретен до того, как GC был тем, и я не верю, что язык мог иметь GC по нескольким причинам (IE Backward compatibilty with C)

Надеюсь, что это поможет.

Ответ 7

Stroustrup сделал несколько хороших комментариев по этому поводу на конференции Going Native 2013 года.

Просто пропустите примерно 25 мкс в это видео. (Я бы порекомендовал посмотреть все видео на самом деле, но это пропускает материал о сборке мусора.)

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

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

Он показывает этот пример:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

Это небезопасно в С++. Но это также небезопасно на Java! В С++, если функция возвращается раньше, delete никогда не будет вызываться. Но если у вас была полная сборка мусора, например, на Java, вы просто получаете предложение о том, что объект будет разрушен "в какой-то момент в будущем" (обновление: это еще хуже, чем это. Java не обещает вызывать финализатор когда-либо - его, возможно, никогда не назовут). Это недостаточно хорошо, если Gadget содержит дескриптор открытого файла или соединение с базой данных или данные, которые вы буферизировали для записи в базу данных в более поздней точке. Мы хотим, чтобы Гаджет был уничтожен, как только он закончил, чтобы как можно скорее освободить эти ресурсы. Вы не хотите, чтобы ваш сервер базы данных боролся с тысячами подключений к базе данных, которые больше не нужны, - он не знает, что ваша программа завершена.

Итак, какое решение? Есть несколько подходов. Очевидный подход, который вы будете использовать для подавляющего большинства ваших объектов:

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

Это занимает меньше символов для ввода. У него нет new в пути. Вам не нужно дважды вводить Gadget. Объект уничтожается в конце функции. Если это то, что вы хотите, это очень интуитивно. Gadget ведут себя так же, как int или double. Предсказуемый, легко читаемый, простой в обучении. Все это "ценность". Иногда большое значение, но ценности легче учить, потому что у вас нет этого "действия на расстоянии", которое вы получаете с указателями (или ссылками).

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

Значимость и продолжительность жизни важны. Большую часть времени проще, если срок службы совпадает с масштабом. Это легче понять и легче учить. Если вам нужна другая жизнь, должно быть очевидно, прочитав код, который вы делаете, используя shared_ptr, например. (Или возвращать (большие) объекты по значению, используя семантику перемещения или unique_ptr.

Это может показаться проблемой эффективности. Что делать, если я хочу вернуть гаджет из foo()? Семантика перемещения С++ 11 облегчает возврат больших объектов. Просто напишите Gadget foo() { ... }, и он будет просто работать и работать быстро. Вам не нужно возиться с && самостоятельно, просто возвращайте вещи по значению, и язык часто сможет выполнять необходимые оптимизации. (Еще до С++ 03 компиляторы отлично справились с задачей избежать ненужного копирования.)

Как сказал Страуступ в другом месте видео (перефразируя): "Только компьютерный ученый будет настаивать на копировании объекта, а затем уничтожить оригинал (смеется аудитория). Почему бы просто не переместить объект прямо в новое место? это то, что ожидают люди (не компьютерные ученые)".

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

Если это не сработает для вас, вы можете использовать unique_ptr, или если это не так, shared_ptr. Хорошо написанный С++ 11 является более коротким, более простым для чтения и более простым в обучении, чем многие другие языки, когда дело доходит до управления памятью.

Ответ 8

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

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

Ответ 10

Одним из основополагающих принципов исходного языка C является то, что память состоит из последовательности байтов, а код должен заботиться только о том, что означают эти байты в тот момент, когда они используются. Modern C позволяет компиляторам налагать дополнительные ограничения, но C включает в себя - и С++ сохраняет - способность разложить указатель на последовательность байтов, собрать любую последовательность байтов, содержащих одни и те же значения, в указатель, а затем использовать этот указатель для доступ к более раннему объекту.

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

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

Ответ 11

Потому что современный C++ не нуждается в сборке мусора.

Bjarne Stroustrup FAQ ответ на этот вопрос говорит:

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


Ситуация для кода, написанного в эти дни (C++ 17 и следуя официальным Основным правилам), выглядит следующим образом:

  • Большая часть кода, связанного с владением памятью, находится в библиотеках (особенно в тех, которые предоставляют контейнеры).
  • В большинстве случаев использование кода, связанного с владением памятью, следует шаблону RAII, поэтому выделение производится при конструировании, а освобождение при уничтожении, что происходит при выходе из области, в которой что-то было выделено.
  • Вы не выделяете или не выделяете память напрямую.
  • Необработанные указатели не владеют памятью (если вы следовали рекомендациям), поэтому вы не сможете утечь, передав их.
  • Если вам интересно, как вы собираетесь передавать начальные адреса последовательностей значений в памяти - вы будете делать это с помощью span; необработанный указатель не требуется.
  • Если вам действительно нужен собственный "указатель", вы используете умные указатели стандартной библиотеки C++ - они не могут просочиться и достаточно эффективны. В качестве альтернативы вы можете передать владение через границы области действия с помощью "указателей владельца". Они необычны и должны использоваться явно; и они позволяют проводить частичную статическую проверку на предмет утечек.

"О да? Но как насчет...

... если я просто напишу код так, как мы писали C++ в старые времена? "

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

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

... если я reintrepret_cast? Или сделать указатель арифметики? Или другие такие хаки?

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

  1. Вы будете делать это редко (с точки зрения мест в коде, не обязательно с точки зрения доли времени выполнения)
  2. Вы бы сделали это только намеренно, а не случайно.
  3. Это будет выделяться в кодовой базе, соответствующей рекомендациям.
  4. Это тот код, в котором вы все равно обойдете GC на другом языке.

... развитие библиотеки? "

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


Итак, это так, как сказал Бьярне: на самом деле нет никакой мотивации собирать мусор вообще, как вы все, но старайтесь не производить мусор. GC становится не проблема с C++.

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

Ответ 12

Все технические разговоры преувеличивают концепцию.

Если вы поместите GC в С++ для всей памяти автоматически, рассмотрите что-то вроде веб-браузера. Веб-браузер должен загрузить полный веб-документ и запустить веб-скрипты. Вы можете хранить переменные web script в дереве документов. В BIG-документе в браузере с множеством открываемых вкладок это означает, что каждый раз, когда GC должен делать полную коллекцию, он также должен проверять все элементы документа.

На большинстве компьютеров это означает, что PAGE FAULTS произойдет. Поэтому главная причина, чтобы ответить на вопрос, что PAGE FAULTS произойдет. Вы узнаете об этом, когда ваш компьютер начнет делать много доступа к диску. Это связано с тем, что GC должен касаться большого количества памяти, чтобы доказать недействительные указатели. Когда у вас есть добросовестное приложение, использующее большое количество памяти, нужно сканировать все объекты, каждый из которых имеет хаос из-за PAGE FAULTS. Ошибка страницы, когда виртуальная память должна считывать обратно в RAM с диска.

Итак, правильное решение состоит в том, чтобы разделить приложение на части, которые нуждаются в GC и тех частях, которые этого не делают. В случае вышеприведенного примера веб-браузера, если дерево документов было выделено с помощью malloc, но javascript работал с GC, тогда каждый раз, когда GC запускает его, он просматривает только небольшую часть памяти и все элементы PAGED OUT памяти для дерево документа не нужно возвращать назад.

Чтобы лучше понять эту проблему, найдите виртуальную память и как она реализована на компьютерах. Все дело в том, что 2 ГБ доступно для программы, когда на самом деле не так много ОЗУ. На современных компьютерах с 2 ГБ оперативной памяти для 32-битной системы это не проблема, если только одна программа запущена.

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

Таким образом, мой ответ, чтобы привести его вкратце, состоит в том, что число PAGE FAULTS, возникающее в результате касания всей памяти, приводит к тому, что полный GC для всех объектов в программе является неосуществимым, и поэтому программист должен просмотреть GC в качестве помощи для такие как скрипты и работа с базами данных, но делают обычные вещи с ручным управлением памятью.

И другой очень важной причиной, конечно же, являются глобальные переменные. Чтобы коллекционер знал, что глобальный указатель переменной находится в GC, для этого потребуются определенные ключевые слова, и, следовательно, существующий код на С++ не будет работать.

Ответ 13

КРАТКОЕ ОТВЕТ: Мы не знаем, как эффективно выполнять сборку мусора (с небольшими затратами времени и пространства) и правильно все время (во всех возможных случаях).

ДОЛГОЙ ОТВЕТ: Так же, как C, С++ - системный язык; это означает, что он используется, когда вы пишете системный код, например, операционную систему. Другими словами, С++ разработан, как и C, с наилучшей производительностью в качестве основной цели. Стандарт языка не добавит никакой функции, которая могла бы помешать достижению производительности.

Это ставит вопрос: почему сборка мусора препятствует работе? Основная причина заключается в том, что, когда дело доходит до реализации, мы [компьютерные ученые] не знаем, как делать сборку мусора с минимальными накладными расходами, для всех случаев. Следовательно, невозможно, чтобы компилятор С++ и система выполнения выполняли сборку мусора эффективно все время. С другой стороны, программист на С++ должен знать свой дизайн/реализацию, и он лучший человек, чтобы решить, как лучше всего делать сборку мусора.

Наконец, если управление (аппаратное обеспечение, детали и т.д.) и производительность (время, пространство, мощность и т.д.) не являются основными ограничениями, то С++ не является инструментом записи. Другой язык может лучше обслуживать и предлагать больше [скрытого] управления временем выполнения с необходимыми накладными расходами.

Ответ 14

Когда вы сравниваете С++ с Java, вы можете сразу увидеть, что С++ не был разработан с неявной сборкой мусора, в то время как Java была.

Наличие таких вещей, как произвольные указатели в C-Style и детерминированных деструкторах, не только замедляет производительность GC-реализаций, но также разрушает обратную совместимость для большого количества С++ - устаревшего кода.

В дополнение к этому, С++ - это язык, который предназначен для запуска как автономный исполняемый файл вместо сложной среды выполнения.

Всего: Да, можно было бы добавить сборку мусора на С++, но для продолжения лучше не делать этого. Стоимость этого будет больше, чем пользы.

Ответ 15

В основном по двум причинам:

  • Потому что он не нужен (IMHO)
  • Потому что он в значительной степени несовместим с RAII, который является краеугольным камнем С++

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

Ответ 16

Наложение сбора мусора действительно представляет собой сдвиг парадигмы на уровне низкого уровня.

Если вы посмотрите на то, как строки обрабатываются на языке с сборкой мусора, вы обнаружите, что они ТОЛЬКО разрешают функции управления строкой высокого уровня и не допускают двоичный доступ к строкам. Проще говоря, все строковые функции сначала проверяют указатели, чтобы увидеть, где находится строка, даже если вы только вытаскиваете байт. Поэтому, если вы выполняете цикл, который обрабатывает каждый байт в строке на языке с сборкой мусора, он должен вычислять базовое местоположение плюс смещение для каждой итерации, потому что он не может знать, когда строка перемещена. Затем вам нужно подумать о кучах, стеках, потоках и т.д. И т.д.