Вопрос

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

С учетом вышесказанного, почему его не добавили?Для C++ уже существуют сборщики мусора.Это просто одна из тех вещей, которые «легче сказать, чем сделать»?Или есть другие причины, по которым он не был добавлен (и не будет добавлен в C++11)?

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

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

Это было полезно?

Решение

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

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

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

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

Общий обзор:

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

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

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

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

В C++0x будет реализована сборка мусора с помощью указателей, созданных с помощью Shared_ptr.

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

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

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

Однако у него нет прозрачной сборки мусора.Тем не менее, это будет отправной точкой для будущих спецификаций C++.

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

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

Другие советы

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

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

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

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

В настоящее время широко распространены два семейства GC:

  • Вид «Отметить и подметать»
  • Тип подсчета ссылок

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

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

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

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

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

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

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

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

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

Языки с GC имеют два обходных пути:

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

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

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

Нельзя быть более неправым.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Что касается того, почему он не встроен, если я правильно помню, он был изобретен до того, как GC стал вещь, и я не верю, что язык мог иметь GC по нескольким причинам (обратная совместимость I.E с C)

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

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

Просто перейдите примерно к 25:50. это видео.(На самом деле я бы порекомендовал посмотреть все видео, но речь идет о сборе мусора.)

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

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

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

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

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

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

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()?Семантика перемещения C++11 упрощает возврат больших объектов.Просто пиши Gadget foo() { ... } и это просто сработает, и сработает быстро.Вам не нужно возиться с && самостоятельно, просто возвращайте данные по значению, и язык часто сможет выполнить необходимую оптимизацию.(Даже до появления C++03 компиляторы замечательно справлялись с задачей избежать ненужного копирования.)

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

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

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

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

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

Чтобы ответить на большинство вопросов «почему» о C++, прочитайте Проектирование и эволюция C++

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

Часто задаваемые вопросы Бьярна Страуструпа ответ по этому вопросу говорит:

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


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

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

"Ах, да?Но что насчет...

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

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

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

...Если я reintrepret_cast?Или выполнять арифметику указателей?Или другие подобные хаки?»

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

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

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

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


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

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

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

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

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

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

Если вы автоматически помещаете GC в C++ для всей памяти, рассмотрите что-то вроде веб-браузера.Веб-браузер должен загрузить полный веб-документ И запустить веб-скрипты.Вы можете хранить переменные веб-скрипта в дереве документа.В БОЛЬШОМ документе в браузере с множеством открытых вкладок это означает, что каждый раз, когда сборщик мусора должен выполнить полную коллекцию, он также должен сканировать все элементы документа.

На большинстве компьютеров это означает, что произойдет ОШИБКА СТРАНИЦЫ.Итак, основная причина ответа на этот вопрос заключается в том, что возникнут ОШИБКИ СТРАНИЦ.Вы узнаете об этом, когда ваш компьютер начнет активно обращаться к диску.Это связано с тем, что сборщику мусора приходится обрабатывать большой объем памяти, чтобы подтвердить недействительные указатели.Если у вас есть добросовестное приложение, использующее много памяти, необходимость сканирования всех объектов в каждой коллекции приводит к хаосу из-за ОШИБОК СТРАНИЦЫ.Страничная ошибка — это когда виртуальную память необходимо прочитать обратно в ОЗУ с диска.

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

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

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

Итак, мой краткий ответ заключается в том, что количество ОШИБОК СТРАНИЦЫ, возникающих в результате обращения ко всей памяти, приводит к тому, что полный сбор мусора для всех объектов в программе становится невозможным, и поэтому программист должен рассматривать сборщик мусора как помощь для таких вещей, как сценарии. и работать с базой данных, но делать обычные вещи с ручным управлением памятью.

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

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

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

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

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

Если вы сравните C++ с Java, вы сразу увидите, что C++ не был разработан с учетом неявной сборки мусора, в отличие от Java.

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

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

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

Главным образом по двум причинам:

  1. Потому что он не нужен (ИМХО)
  2. Потому что он практически несовместим с RAII, который является краеугольным камнем C++.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top