В двух словах
Завершение не является простым делом для сборщиков мусора. Его легко использовать с GC для подсчета ссылок, но это семейство GC часто неполное, требующее компенсации утечек памяти путем явного запуска уничтожения и завершения некоторых объектов и структур. Отслеживание сборщиков мусора гораздо эффективнее, но значительно усложняет идентификацию объекта, подлежащего доработке и уничтожению, в отличие от простого определения неиспользуемой памяти, что требует более сложного управления, затрат времени и пространства и сложности реализация.
Введение
Я предполагаю, что вы спрашиваете, почему языки сборки мусора не обрабатывают автоматически уничтожение / финализацию в процессе сбора мусора, как указано в замечании:
Мне крайне не хватает того, что эти языки рассматривают память как единственный ресурс, которым стоит управлять. Как насчет сокетов, файловых дескрипторов, состояний приложений?
Я не согласен с принятым ответом, данным kdbanman . Хотя изложенные факты в основном верны, хотя и сильно склонны к подсчету ссылок, я не верю, что они правильно объясняют ситуацию, о которой пойдет речь в этом вопросе.
Я не верю, что терминология, разработанная в этом ответе, является большой проблемой, и она с большей вероятностью может сбить с толку. Действительно, как представлено, терминология в основном определяется способом активации процедур, а не тем, что они делают. Дело в том, что во всех случаях необходимо завершить объект, который больше не нужен, с помощью некоторого процесса очистки и освободить все ресурсы, которые он использовал, память является лишь одним из них. В идеале все это должно выполняться автоматически, когда объект больше не используется, с помощью сборщика мусора. На практике GC может отсутствовать или иметь недостатки, и это компенсируется явным срабатыванием программой доработки и восстановления.
Явное тригеринг в программе является проблемой, так как он может затруднить анализ ошибок программирования, когда объект, который все еще используется, явно завершается.
Следовательно, гораздо лучше полагаться на автоматическую сборку мусора для восстановления ресурсов. Но есть две проблемы:
некоторые методы сбора мусора допускают утечки памяти, которые препятствуют полной утилизации ресурсов. Это хорошо известно для подсчета ссылок GC, но может появиться для других методов GC при использовании некоторых организаций данных без осторожности (точка не обсуждается здесь).
в то время как методика GC может быть полезна для идентификации ресурсов памяти, которые больше не используются, финализация объектов, содержащихся в них, может быть непростой, и это усложняет проблему восстановления других ресурсов, используемых этими объектами, что часто является целью завершения.
Наконец, важный момент, который часто забывают, заключается в том, что циклы GC могут быть вызваны чем угодно, не только нехваткой памяти, если предусмотрены надлежащие зацепки и если стоимость цикла GC считается оправданной. Следовательно, вполне нормально инициировать сборщик мусора, когда отсутствует какой-либо ресурс, в надежде освободить его.
Подсчет ссылок сборщиков мусора
Подсчет ссылок является слабой техникой сбора мусора , которая не будет правильно обрабатывать циклы. Он действительно будет слаб при разрушении устаревших структур и восстановлении других ресурсов просто потому, что он слаб при восстановлении памяти. Но финализаторы легче всего использовать с сборщиком мусора (GC) подсчета ссылок, поскольку GC ref-count восстанавливает структуру, когда его ref ref уменьшается до 0, когда его адрес известен вместе с его типом, либо статически или динамически. Следовательно, можно восстановить память точно после применения правильного финализатора и рекурсивного вызова процесса для всех указанных объектов (возможно, через процедуру финализации).
В двух словах, финализация легко реализуется с помощью RefCing GC, но страдает от «незавершенности» этого GC, действительно из-за круговых структур, в той же степени, в какой страдает восстановление памяти. Другими словами, при подсчете ссылок память управляется так же плохо, как и другие ресурсы, такие как сокеты, файловые дескрипторы и т. Д.
Действительно, неспособность Ref Count GC восстанавливать циклические структуры (в общем) может рассматриваться как утечка памяти . Вы не можете ожидать, что все GC, чтобы избежать утечек памяти. Это зависит от алгоритма GC и от динамически доступной информации о структуре типов (например, в
консервативном GC ).
Отслеживание сборщиков мусора
Более мощное семейство GC, без таких утечек, - это семейство трассировки, которое исследует живые части памяти, начиная с хорошо идентифицированных корневых указателей. Все части памяти, которые не посещаются в этом процессе трассировки (которые на самом деле могут быть разложены различными способами, но я должен упростить), являются неиспользуемыми частями памяти, которые могут быть таким образом восстановлены 1 . Эти сборщики восстановят все части памяти, к которым программа больше не сможет получить доступ, независимо от того, что она делает. Он восстанавливает круговые структуры, и более продвинутые GC основаны на некоторой вариации этой парадигмы, иногда очень сложной. В некоторых случаях его можно комбинировать с подсчетом ссылок и компенсировать его недостатки.
Проблема в том, что ваше утверждение (в конце вопроса):
Языки, которые предлагают автоматическую сборку мусора, являются основными кандидатами для поддержки уничтожения / завершения объекта, поскольку они знают со 100% уверенностью, когда объект больше не используется.
технически некорректно для отслеживания коллекторов.
Что известно со 100% уверенностью, это то, какие части памяти больше не используются . (Точнее, следует сказать, что они больше недоступны , поскольку некоторые части, которые больше не могут использоваться в соответствии с логикой программы, все еще считаются используемыми, если в программе все еще есть бесполезный указатель на них. данные.) Но необходима дальнейшая обработка и соответствующие структуры, чтобы узнать, какие неиспользуемые объекты могли храниться в этих теперь неиспользуемых частях памяти . Это не может быть определено из того, что известно о программе, так как программа больше не связана с этими частями памяти.
Таким образом, после прохода сборки мусора у вас остаются фрагменты памяти, которые содержат объекты, которые больше не используются, но априори нет способа узнать, что это за объекты, чтобы применить правильную финализацию. Кроме того, если коллектор трассировки является типом метки и развертки, может случиться так, что некоторые фрагменты могут содержать объекты, которые уже были завершены в предыдущем проходе GC, но с тех пор не использовались по причинам фрагментации. Однако это можно решить с помощью расширенной явной типизации.
В то время как простой сборщик просто восстановил бы эти фрагменты памяти, без дальнейших церемоний, для завершения требуется специальный проход, чтобы исследовать эту неиспользуемую память, идентифицировать содержащиеся в ней объекты и применять процедуры финализации. Но такое исследование требует определения типа объектов, которые там хранились, и определение типа также необходимо для применения надлежащего завершения, если таковое имеется.
Таким образом, это подразумевает дополнительные затраты времени GC (дополнительный проход) и, возможно, дополнительные затраты памяти, чтобы сделать правильную информацию о типе доступной во время этого прохода различными способами. Эти затраты могут быть значительными, поскольку часто требуется завершить работу только с несколькими объектами, тогда как время и пространство могут касаться всех объектов.
Другой момент заключается в том, что временные и пространственные накладные расходы могут касаться выполнения программного кода, а не только выполнения GC.
Я не могу дать более точный ответ, указывая на конкретные вопросы, потому что я не знаю специфику многих языков, которые вы перечислите. В случае с C печатание - очень сложная проблема, которая ведет к развитию консервативных коллекционеров. Я думаю, что это влияет и на C ++, но я не специалист по C ++. Это, кажется, подтверждается Гансом Бёмом, который проводил большую часть исследований по консервативному ГК. Консервативный GC не может систематически восстанавливать всю неиспользуемую память именно потому, что может отсутствовать точная информация о типе данных. По той же причине он не сможет систематически применять процедуры завершения.
Таким образом, можно делать то, что вы просите, как вы знаете из некоторых языков. Но это не бесплатно. В зависимости от языка и его реализации, это может повлечь за собой затраты, даже если вы не используете эту функцию. Различные методы и компромиссы могут рассматриваться для решения этих проблем, но это выходит за рамки разумного размера ответа.
1 - это абстрактное представление коллекции трассировки (включающее в себя как ГХ для копирования, так и для разметки и очистки), все меняется в зависимости от типа сборщика трассировки, а исследование неиспользуемой части памяти различается в зависимости от того, копируется или помечается и развертка используется.
finalize
/destroy
это ложь? Нет гарантии, что это когда-либо будет выполнено. И даже если вы не знаете, когда (с учетом автоматической сборки мусора) и, если необходимо, контекст все еще существует (возможно, он уже был собран). Поэтому безопаснее обеспечить согласованное состояние другими способами, и можно заставить программиста сделать это.