Почему в таких языках, как C и C ++, нет сборки мусора, а в Java - нет? [закрыто]

57

Ну, я знаю, что есть такие вещи, как malloc / free для C и new / using-a-destructor для управления памятью в C ++, но мне было интересно, почему нет «новых обновлений» для этих языков, которые позволяют пользователю есть возможность вручную управлять памятью, или чтобы система делала это автоматически (сборка мусора)?

Что-то вроде вопроса новичка, но был в CS только около года.

Dark Templar
источник
9
В этом семестре у нас есть модуль по разработке iPhone. После 2-х лет написания приложений для Android этот вопрос довольно сильно задет большинству класса. Только теперь мы видим, сколько часов на самом деле сэкономило нам Java, избавляя нас от необходимости отслеживать неприятные ошибки в управлении памятью и не писать код на листе.
Сиами
7
@NullUserException, поскольку он не определяет способ восстановления памяти, который в значительной степени подразумевает сборщик мусора.
Уинстон Эверт
1
@ bizso09: Вы уже смотрели на ARC? Нет необходимости в медленном / жирном / недетерминированном GC, когда вы получаете системную поддержку для подсчета ссылок: developer.apple.com/technologies/ios5
JBRWilkinson
3
Ответы на этот довольно хороший вопрос полны религиозной чуши.
Абатищев
1
В C и C ++ можно взять указатель, привести его к int и добавить к нему число. Позже вычтите число из int и приведите результат обратно к указателю. Вы получите тот же указатель, что и раньше. Удачи в реализации GC, который НЕ собирает эту память, пока ее адрес хранится только в переменной, которая также имеет другое значение. Я знаю, что пример глуп, но в связанном списке XOR используется нечто подобное. Я бы опубликовал это как ответ, но вопрос закрыт.
Мариан Спаник

Ответы:

71

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

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

kylben
источник
26
Вторичная проблема заключается в том, что сборщик мусора недетерминирован. Объект может или не может оставаться в памяти еще долго после того, как программа «сбросила» его. Жизненные циклы пересчета являются детерминированными, когда последняя ссылка отбрасывается, память удаляется. Это имеет значение не только для эффективности памяти, но и для отладки. Распространенной ошибкой программирования является объект «зомби», эталонная память которого была теоретически удалена. GC с большей вероятностью замаскирует этот эффект и создаст ошибки, которые периодически и чрезвычайно трудно выследить.
kylben
22
- современные gc не отслеживают распределение и не подсчитывают ссылки. Они строят график из всего, что в данный момент находится в стеке, и просто уплотняют и стирают все остальное (упрощенно), и GC обычно приводит к снижению языковой сложности. Даже выигрыш в производительности сомнителен.
Джоэл Коухорн
13
Э-э, @kylben, весь смысл автоматической вставки GC в язык состоит в том, что становится невозможным ссылаться на объекты-зомби, потому что GC освобождает только те объекты, на которые невозможно ссылаться! Когда вы делаете ошибки с ручным управлением памятью, вы получаете вид трудных для отслеживания ошибок, о которых вы говорите.
Бен
14
-1, GC не считает ссылки. Кроме того, в зависимости от используемой памяти и схемы распределения, сборщик мусора может работать быстрее (с дополнительными затратами на использование памяти). Таким образом, аргумент о производительности тоже заблуждение. Только близость к металлу является действительной точкой на самом деле.
Deadalnix
14
Ни Java, ни C # не используют подсчет ссылок: схемы GC, основанные на подсчете ссылок, довольно примитивны в сравнении и работают намного хуже, чем современные сборщики мусора (в основном потому, что им нужно выполнять запись в память для изменения количества ссылок при каждом копировании ссылки!)
mikera
44

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

Зачем вам язык без стандарта для управления памятью? Это восходит к происхождению C как «портативная сборка». Существует множество случаев использования аппаратных средств и алгоритмов, которые могут извлечь выгоду или даже потребовать специализированных методов управления памятью. Насколько я знаю, нет способа полностью отключить встроенное управление памятью Java и заменить его своим. Это просто неприемлемо в некоторых ситуациях с высокой производительностью / минимальными ресурсами. C обеспечивает почти полную гибкость, чтобы точно выбрать, какую инфраструктуру будет использовать ваша программа. Заплаченная цена состоит в том, что язык C очень мало помогает в написании правильного кода без ошибок.

Чарльз Э. Грант
источник
2
+1 один за общий хороший ответ, но также и за «Цена заплачена за то, что язык C очень мало помогает в написании правильного кода без ошибок»
Shivan Dragon
2
C действительно имеет управление памятью - но оно просто работает, поэтому люди едва замечают это. Там есть статическая память, регистры и стек. Пока вы не начнете выделять из кучи, вы в порядке и денди. Это куча распределения, которая все портит. Что касается Java, каждый может написать свою собственную среду выполнения Java - есть из чего выбирать, включая то, что можно назвать «Системное Java». .NET может делать практически все, что может C - он отстает только от собственных возможностей C ++ (например, классы управляются только в .NET). Конечно, у вас также есть C ++. NET, который имеет все, что делает C ++, и все, что делает .NET.
Луаан
1
@Luaan Я бы сказал, что это очень щедрое определение «управления памятью»: «Пока вы не начнете выделять из кучи, у вас все в порядке и денди. Это распределение кучи, которое все портит», это как сказать, что машина совершенно хороший самолет, он просто не умеет летать.
Чарльз Грант
1
@ CharlesE.Grant Ну, чисто функциональный язык может делать все с таким управлением памятью. То, что выделение кучи является хорошим компромиссом в некоторых случаях, не означает, что он является эталоном для всех языков / сред выполнения. Это не значит, что управление памятью перестает быть «управлением памятью» просто потому, что оно простое, прямое, скрытое за кулисами. Разработка статического распределения памяти - это все еще управление памятью, так же как и хорошее использование стека и всего, что у вас есть.
Луаан
«любая стандартная совместимая реализация» не соответствует действительности, только для стандартной совместимой реализации хост-среды. Некоторые платформы / стандартные библиотеки, большинство для 8 или 16-битного встроенного микроконтроллера, не предоставляют malloc()или free(). (например, MLAP-компиляторы для PIC)
12431234123412341234123
32

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

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, но также достаточно хорош для большинство целей. К сожалению, серебряной пули не существует, но знание различных вариантов поможет вам выбрать правильный вариант для любой программы, которую вы сейчас пытаетесь построить.

Daniel Pryden
источник
4
Это фактический ответ на вопрос
coredump
1
Для части c ++, в настоящее время вы должны смотреть на std :: unique_ptr и std :: move :)
Никлас Ларссон
@NiclasLarsson: Я не уверен, что понимаю вашу точку зрения. Вы говорите, что std::unique_ptrэто «языковая поддержка непрозрачных ссылок»? (Это была не та поддержка, которую я имел в виду, и я также не думаю, что этого достаточно, если поддержка прямого манипулирования памятью не была также удалена из C ++.) Я упоминаю умные указатели в своем ответе, и я бы рассмотрел std:unique_ptrумный указатель поскольку он действительно выполняет подсчет ссылок, он поддерживает только особые случаи, когда количество ссылок равно нулю или единице (и std::moveявляется механизмом обновления счетчика ссылок).
Даниэль Приден
std::unique_ptrне имеет счетчика ссылок и не std::moveимеет никакого отношения к ссылкам вообще (таким образом, "нет" снижения производительности). Хотя я понимаю вашу точку зрения, так как у std::shared_ptrнее есть счетчик ссылок, который является бездействием, обновленным std::move:)
Никлас Ларссон
2
@ Mike76: На стороне выделения распределитель GC будет работать примерно так же быстро, как и выделение стека, и GC может одновременно освобождать тысячи объектов. Независимо от того, что вы делаете с реализацией подсчета ссылок, распределение и освобождение никогда не будут быстрее, чем mallocи free. Так что да, сборщик мусора может быть значительно быстрее. (Обратите внимание, что я сказал «может быть» - конечно, на точную производительность каждой программы влияет множество факторов.)
Даниэль Приден
27

Потому что при использовании возможностей C ++ в этом нет необходимости.

Херб Саттер: « Я не писал удалить годами ».

см. Написание современного кода на C ++: как C ++ развивался на протяжении многих лет 21:10

Это может удивить многих опытных программистов на C ++.

Лиор Коган
источник
Интересно. Мой материал для чтения на сегодня.
Surfasb
Бах, видео. Но тем не менее, уже интересно.
Surfasb
2
интересное видео. 21 минута и 55 минут были лучшими. Жаль, что вызовы WinRT все еще выглядят как C ++ / CLI bumpf.
gbjbaanb
2
@ dan04: это правда. Но тогда, если вы напишите на C, вы получите то, что просите.
DeadMG
6
Управление умными указателями не более требовательно, чем проверка наличия ненужных ссылок в среде с сборкой мусора. Поскольку GC не может читать ваши мысли, это тоже не волшебство.
Тамас Селеи
15

«Все» сборщик мусора - это процесс, который периодически запускается для проверки наличия в памяти объектов, на которые нет ссылок, и их удаления. (Да, я знаю, что это грубое упрощение). Это не свойство языка, а рамки.

Есть сборщики мусора , написанные для C и C ++ - это одно , например.

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

оборота ChrisF
источник
1
Но будущие написанные программы начнут использовать сборщик мусора, нет?
Темный тамплиер
5
Хотя сборка мусора теоретически независима от любого языка программирования, довольно сложно написать полезный GC для C / C ++ и даже невозможно сделать надежный (по крайней мере, такой же надежный, как Java) - причина, по которой Java может тянуть его это потому, что он работает в контролируемой виртуальной среде. И наоборот, язык Java разработан для GC, и вам будет сложно написать компилятор Java, который не выполняет GC.
tdammers
4
@tdammers: Я согласен, что сборка мусора должна поддерживаться языком, чтобы это было возможно. Однако главное - не виртуализация и контролируемая среда, а строгая типизация. C и C ++ слабо типизированы, поэтому они позволяют хранить такие вещи, как сохранение указателя в целочисленной переменной, восстановление указателей из смещений и такие вещи, которые не позволяют сборщику надежно сказать, что достижимо (C ++ 11 запрещает последнему разрешать по крайней мере консервативные коллекционеры). В Java вы всегда знаете, что такое ссылка, поэтому вы можете точно ее собрать, даже если она скомпилирована в native.
Ян Худек
2
@ ThorbjørnRavnAndersen: Я могу написать действительную программу на C, которая хранит указатели таким образом, что ни один сборщик мусора не сможет их найти. Если затем зацепить сборщик мусор mallocи free, вы нарушите правильную программу.
Бен Фойгт
2
@ ThorbjørnRavnAndersen: Нет, я бы не стал звонить, freeпока не покончу с этим. Но предлагаемый вами сборщик мусора, который не освобождает память до тех пор, пока я явно не вызову, freeвовсе не сборщик мусора.
Бен Фойгт
12

C был разработан в эпоху, когда сборка мусора была едва ли возможной. Он также был предназначен для использования там, где сборка мусора обычно не работает - «голое железо», среды реального времени с минимальным объемом памяти и минимальной поддержкой времени выполнения. Помните, что C был языком реализации для первого Unix, который работал на pdp-11 с 64 * K * байтами памяти. Изначально C ++ был расширением C - выбор уже был сделан, и очень сложно перенести сборку мусора на существующий язык. Это то, что нужно встроить с первого этажа.

ddyer
источник
9

У меня нет точных цитат, но Бьярне и Херб Саттер говорят что-то вроде:

C ++ не нуждается в сборщике мусора, потому что в нем нет мусора.

В современном C ++ вы используете умные указатели и поэтому не имеете мусора.

ronag
источник
1
что такое умные указатели?
Темный тамплиер
11
если бы это было так просто, никто бы не внедрил GC.
Deadalnix
7
@deadalnix: Правильно, потому что никто никогда не реализует ничего слишком сложного, медленного, раздутого или ненужного. Все программное обеспечение всегда эффективно на 100%, верно?
Зак
5
@deadalnix - C ++ подход к управлению памятью новее, чем сборщики мусора. RAII был изобретен Бьярном Страуструпом для C ++. Очистка деструктора - более старая идея, но правила обеспечения безопасности исключений являются ключевыми. Я не знаю, когда именно, когда сама идея была впервые описана, но первый стандарт C ++ был завершен в 1998 году, и Stroustrups «Дизайн и эволюция C ++» не был опубликован до 1994 года, а исключения были относительно недавним дополнением к C ++ - я думаю, что после публикации «Справочного руководства по С ++» в 1990 году. GC был изобретен в 1959 году для Lisp.
Steve314 15.10.11
1
@deadalnix - знаете ли вы, что по крайней мере одна виртуальная машина Java использовала GC для подсчета ссылок, который (почти) мог быть реализован с использованием RAII в стиле C ++ с использованием класса интеллектуальных указателей - именно потому, что он был более эффективен для многопоточного кода, чем существующие виртуальные машины? См. Www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf. Одной из причин, почему вы не видите этого в C ++ на практике, является обычная коллекция GC - она ​​может собирать циклы, но не может выбрать безопасный порядок деструкторов при наличии циклов и, следовательно, не может обеспечить надежную очистку деструкторов.
Steve314 15.10.11
8

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

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

Уинстон Эверт
источник
6

Можете ли вы представить написание обработчика устройства на языке с сборкой мусора? Сколько битов может прийти по линии во время работы GC?

Или операционная система? Как вы можете запустить сборку мусора еще до того, как запустите ядро?

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

Джеймс Андерсон
источник
2
С хорошим для высокого уровня? Я нюхнул свой напиток по всей клавиатуре.
DeadMG
5
Ну, он сказал "много задач более высокого уровня". Он мог считать троллей (раз, два, много ...). И он на самом деле не сказал выше, чем что. Шутки в сторону, хотя, это правда , - свидетельство того , что многие значимые проекты более высокого уровня , которые были успешно разработаны в C. Там может быть лучший выбор в настоящее время для многих из этих проектов, но рабочий проект более убедительные доказательства , чем спекуляции о том , что может Был.
Steve314
Есть несколько управляемых операционных систем, и они работают довольно хорошо. Фактически, когда вы делаете всю систему управляемой, снижение производительности от использования управляемого кода падает еще ниже, вплоть до того, чтобы быть быстрее, чем неуправляемый код в реальных сценариях. Конечно, это все «исследовательские ОС» - практически невозможно сделать их совместимыми с существующим неуправляемым кодом, кроме как сделать полностью виртуализированную неуправляемую ОС внутри управляемой ОС. Microsoft действительно предложила в какой-то момент заменить Windows Server одним из них, так как все больше серверного кода пишется в .NET.
Луаан
6

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

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

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

hugomg
источник
1
Где-то на programmers.se или SO, кто-то сделал мне заявление о том, что кто-то работает над самозагрузочной сборкой мусора - IIRC в основном реализует виртуальную машину с использованием языка GC, а подмножество начальной загрузки используется для реализации самого GC. Я забыл имя. Когда я изучил это, оказалось, что они в основном никогда не достигли скачка от подмножества без GC к уровню рабочего GC. Это является в принципе возможно, но AFAIK оно никогда не было достигнуто на практике - это, конечно, дело делать вещи трудный путь.
Steve314
@ Steve314: Я хотел бы увидеть это, если вы когда-нибудь вспомните, где вы его нашли!
hugomg
нашел это! См. Комментарии к stackoverflow.com/questions/3317329/… со ссылкой на Klein VM. Часть проблемы с ее обнаружением - вопрос закрыт.
Steve314 15.10.11
Кстати, я не могу начать свои комментарии с @missingno - что дает?
Steve314
@ steve314: После получения ответа на эту ветку я уже получаю уведомление обо всех комментариях. Выполнение @ -post в этом случае было бы излишним и не разрешалось SE (не спрашивайте меня, почему ). (Но настоящая причина в том, что мой номер отсутствует)
hugomg
5

Есть различные проблемы, в том числе ...

  • Хотя GC был изобретен до C ++ и, возможно, до C, и C, и C ++ были реализованы до того, как GC были широко приняты как практические.
  • Вы не можете легко реализовать язык и платформу GC без базового языка без GC.
  • Хотя GC явно более эффективен, чем не-GC, для типичного кода приложений, разработанного в типичных временных масштабах и т. Д., Существуют проблемы, когда большие усилия по разработке являются хорошим компромиссом, а специализированное управление памятью превзойдет GC общего назначения. Кроме того, C ++ обычно более эффективен, чем большинство языков GC, даже без каких-либо дополнительных усилий по разработке.
  • GC не всегда безопаснее, чем RAII в стиле C ++. RAII позволяет автоматически очищать ресурсы, кроме памяти, в основном потому, что поддерживает надежные и своевременные деструкторы. Они не могут быть объединены с обычными методами GC из-за проблем с контрольными циклами.
  • Языки GC имеют свои характерные виды утечек памяти, особенно связанные с памятью, которая никогда не будет использоваться снова, но там, где существовали ссылки, которые никогда не обнулялись и не перезаписывались. Необходимость сделать это явно не отличается в принципе от необходимости deleteили freeявно. Подход GC по-прежнему имеет преимущество - нет висячих ссылок - и статический анализ может выявить некоторые случаи, но, опять же, нет единого идеального решения для всех случаев.

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

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

Rep-whoring ссылки на похожие ответы моих ...

оборота Steve314
источник
4

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

Вполне возможно, что единственный указатель на объект будет сохранен в аппаратном регистре на некотором периферийном устройстве. Поскольку сборщик мусора не узнает об этом, он подумает, что объект недоступен, и соберет его.

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

Так что теперь вам нужно сочетание неподвижных буферов DMA и объектов, управляемых GC, что означает, что у вас есть все недостатки обоих.

Бен Фойгт
источник
Можно утверждать, что все недостатки обоих, но меньше случаев каждого недостатка, и то же самое для преимуществ. Понятно, что сложнее иметь больше видов управления памятью, но также можно избежать сложности, выбрав правильную лошадь для каждого курса в вашем коде. Вряд ли, я думаю, но там есть теоретический пробел. Раньше я размышлял о смешивании GC и не-GC на одном и том же языке, но не для драйверов устройств - больше для того, чтобы иметь в основном GC-приложение, но с некоторыми библиотеками низкоуровневой структуры данных с ручным управлением памятью.
Steve314
@ Steve314: Разве вы не сказали бы, что помнить, какие объекты нужно освободить вручную, так же обременительно, как помнить, чтобы освободить все? (Конечно, умные указатели могут помочь с любым из них, поэтому ни одна из них не является большой проблемой). И вам нужны разные пулы для объектов, управляемых вручную, по сравнению с собранными / сжимаемыми объектами, поскольку сжатие не работает хорошо, когда повсюду разбросаны фиксированные объекты. Так что много лишних сложностей ни за что.
Бен Фойгт
2
Нет, если есть четкое разделение между кодом высокого уровня, который все является GC, и кодом низкого уровня, который отказывается от GC. В основном я разработал эту идею, глядя на D несколько лет назад, что позволяет вам отказаться от GC, но не позволяет вам вернуться обратно. Возьмем, к примеру, библиотеку B + tree. Контейнер в целом должен быть GC, но, вероятно, нет узлов структуры данных - более эффективно выполнять настраиваемое сканирование только через конечные узлы, чем когда GC выполняет рекурсивный поиск по узлам ветвления. Тем не менее, это сканирование должно сообщать о содержащихся элементах в GC.
Steve314
Дело в том, что это часть функциональности. Обработка узлов дерева B + как специального управления памятью WRT ничем не отличается от обработки их как специальных WRT, являющихся узлами дерева B +. Это инкапсулированная библиотека, и код приложения не должен знать, что поведение GC было обойдено / особым образом. За исключением того, что, по крайней мере, в то время это было невозможно в D - как я уже сказал, нет никакого способа вернуться назад и сообщить о содержащихся предметах в GC в качестве потенциальных корней GC.
Steve314
3

Потому что C & C ++ - это языки относительно низкого уровня, предназначенные для общего назначения, даже, например, для запуска на 16-разрядном процессоре с 1 МБ памяти во встроенной системе, которая не может позволить себе тратить память на gc.

Petruza
источник
1
"Встроенная система"? В то время, когда C был стандартизирован (1989), он должен был уметь работать с ПК с 1 МБ памяти.
Ден04
Я согласен, я привел более актуальный пример.
Петруза
1MB ??? Святой Шмолей, кому когда-нибудь понадобится столько оперативной памяти? </ billGates>
Марк К Коуэн,
2

В C ++ и C. есть сборщики мусора. Не знаю, как это работает в C, но в C ++ вы можете использовать RTTI для динамического обнаружения графа объектов и использования его для сборки мусора.

Насколько мне известно, вы не можете написать Java без сборщика мусора. Небольшой поиск обнаружил это .

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

оборота back2dos
источник
А также, что выделенные сборщики мусора лучше реализованы, более эффективны и лучше вписываются в язык. :)
Макс
Нет, вы не можете использовать RTTI для динамического обнаружения графа объектов в C / C ++: это простые старые объекты данных, которые все портят. Просто отсутствует информация RTTI, хранящаяся в простом старом объекте данных, которая позволила бы сборщику мусора различать указатели и не указатели в этом объекте. Что еще хуже, указатели не обязательно должны быть идеально выровнены на всем оборудовании, поэтому, учитывая 16-байтовый объект, существует 9 возможных положений, в которых может храниться 64-битный указатель, только два из которых не перекрываются.
начальник
2

Это компромисс между производительностью и безопасностью.

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

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

Иногда в этих дебатах может быть небольшое «религиозное» преимущество - будьте осторожны!

adrianmcmenamin
источник
1

Вот список присущих GC проблем, которые делают его непригодным для использования на системном языке, таком как C:

  • GC должен работать ниже уровня кода, объектами которого он управляет. Такого уровня в ядре просто нет.

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

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

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

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

  • GC по своей сути медленный бизнес. Программисты, которые были общены с Java, могут не осознавать этого, но программы могут быть на порядок быстрее, если они не реализованы в Java. И одним из факторов, которые делают Java медленным, является GC. Это то, что исключает использование в суперкомпьютерах языков GCed, таких как Java. Если энергопотребление вашей машины составляет миллион в год, вы не хотите платить даже 10% от этого за сборку мусора.

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

cmaster
источник