Почему в C ++ нет сборщика мусора? - PullRequest
253 голосов
/ 29 сентября 2008

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

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

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

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

Ответы [ 16 ]

4 голосов
/ 11 июня 2017

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

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

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

3 голосов
/ 21 августа 2016

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

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

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

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

3 голосов
/ 19 ноября 2012

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

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

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

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

3 голосов
/ 24 октября 2011

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

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

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

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

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

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

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

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

0 голосов
/ 27 января 2018

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

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

0 голосов
/ 08 ноября 2017

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

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

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

...