Зачем собирать мусор, если есть умные указатели

67

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

И в других языках, таких как C #, если все ссылки обрабатываются как интеллектуальные указатели (за исключением RAII), по спецификации и по реализации, все еще будет ли необходимость в сборщиках мусора? Если нет, то почему это не так?

Gulshan
источник
1
После того, как я задал этот вопрос, я понял одну вещь: умным указателям нужен RAII для управления автоматическим освобождением .
Гульшан
8
Умные указатели означают использование RAII для GC;)
Дарио
Хех, у c # должна быть опция для обработки всей "сборки мусора" с помощью RAII. Циркулярные ссылки могут быть обнаружены при завершении работы приложения, все, что нам нужно, это увидеть, какие выделения все еще находятся в памяти после освобождения Program.cs-класса. Затем циркулярные ссылки можно заменить недельными ссылками.
AareP

Ответы:

67

Итак, какой смысл использовать сборщик мусора?

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

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

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

  • Задержка . Типичные реализации интеллектуальных указателей позволяют лавинам деструкторов приводить к неограниченным временам паузы. Другие формы сбора мусора являются гораздо более инкрементными и даже могут быть в режиме реального времени, например, беговая дорожка Бейкер.

Джон Харроп
источник
23
Не могу поверить, что этот ответ закончился лучшим ответом. Он показывает полное отсутствие понимания интеллектуальных указателей C ++ и делает утверждения, которые настолько не соответствуют действительности, что это просто смешно. Во-первых, умный указатель, который в хорошо спроектированном фрагменте кода C ++ будет наиболее доминирующим, это уникальный указатель, а не указатель общего ресурса. ru.cppreference.com/w/cpp/memory/unique_ptr И, во-вторых, я не могу поверить, что вы на самом деле заявляете о преимуществах «производительности» и преимуществах недетерминированного сбора мусора в реальном времени по сравнению с интеллектуальными указателями.
user1703394
4
@ user1703394 Похоже, что ответчик имел в виду общие указатели (правильно или неправильно, я не совсем уверен, что предлагают OP), которые менее производительны, чем недетерминированная сборка мусора.
Натан Купер
8
Все это аргументы соломенного человека, и они действительны только в том случае, если вы либо полностью игнорируете реальный вопрос, либо игнорируете фактические схемы использования различных типов интеллектуальных указателей. Вопрос был об умных указателях. Да, shared_ptr - это умный указатель, и да, shared_ptr - самый дорогой из умных указателей, но нет, нет фактического аргумента для его повсеместного использования, чтобы приблизить любой аргумент производительности к значению. Серьезно, этот ответ следует перенести на вопрос о подсчете ссылок. Я плохой ответ подсчета ссылок на хороший вопрос умного указателя.
user1703394
4
«Умные указатели - не более широкое понятие», серьезно? Вы не представляете, насколько это утверждение подрывает все возможные аргументы, которые вы до сих пор приводили. Может быть, стоит взглянуть на владение Rust и переместить семантику: koerbitz.me/posts/… Людям , имеющим исторический опыт работы с C ++, легко упустить тот факт, что C ++ 11 / C ++ 14 с моделью памяти улучшен Указатели и семантика перемещения - это совершенно другой зверь, чем их предшественники. Посмотрите, как Rust это делает, он чище, чем C ++, и дает свежую перспективу.
user1703394
6
@ user1703394: «Неограниченные паузы из-за деструкторов - неудачное свойство RAII, используемого для ресурсов, не связанных с памятью». Нет, это не имеет ничего общего с ресурсами, не относящимися к памяти.
Джон Харроп
63

Поскольку никто не смотрел на это с этой точки зрения, я перефразирую ваш вопрос: зачем вводить что-то в язык, если вы можете сделать это в библиотеке? Игнорирование конкретных реализаций и синтаксических подробностей, GC / умные указатели - в основном частный случай этого вопроса. Зачем определять сборщик мусора в самом языке, если вы можете реализовать его в библиотеке?

Есть несколько ответов на этот вопрос. Самое главное первое:

  1. Вы гарантируете, что весь код может использовать его для взаимодействия. Я думаю, что это главная причина, по которой повторное использование кода и совместный доступ к нему действительно не взлетели до Java / C # / Python / Ruby. Библиотеки должны общаться, и единственный надежный общий язык, который у них есть, - это то, что находится в самой спецификации языка (и, в некоторой степени, в его стандартной библиотеке). Если вы когда-либо пытались повторно использовать библиотеки в C ++, вы, вероятно, испытали ужасную боль, которую не вызывает стандартная семантика памяти. Я хочу передать структуру в какую-то библиотеку. Я передаю ссылку? Указатель? scoped_ptr?smart_ptr? Я передаю право собственности или нет? Есть ли способ указать это? Что если lib нужно выделить? Должен ли я дать ему распределитель? Не делая управление памятью частью языка, C ++ заставляет каждую пару библиотек согласовывать здесь свою собственную конкретную стратегию, и очень трудно заставить их всех согласиться. GC делает это полной проблемой.

  2. Вы можете разработать синтаксис вокруг него. Поскольку C ++ не инкапсулирует само управление памятью, он должен предоставить ряд синтаксических хуков, чтобы позволить пользовательскому коду выразить все детали. У вас есть указатели, ссылки, constоператоры разыменования, операторы косвенного обращения, адреса и т. Д. Если вы внедрите управление памятью в сам язык, синтаксис может быть разработан вокруг этого. Все эти операторы исчезают, и язык становится чище и проще.

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

необычайно щедрый
источник
Фантастический ответ! Если бы я только мог поднять голос несколько раз ...
Дин Хардинг
10
Стоит отметить, что сборка мусора фактически реализована не на самом языке C #, а в .NET Framework , в частности Common Language Runtime (CLR).
Роберт Харви
6
@RobertHarvey: Это не реализовано языком, но не будет работать без сотрудничества с языком. Например, компилятор должен включать информацию, указывающую в каждой точке кода местоположение каждого регистра или смещения фрейма стека, которое содержит ссылку на неподкрепленный объект. Это абсолютный инвариант без исключений , который не может быть поддержан без языковой поддержки.
Суперкат
Основное преимущество того, что GC поддерживает язык и требуемую среду, состоит в том, что она гарантирует, что никогда не будет ссылок на память, которая может быть выделена для какой-либо другой цели. Если кто-то вызывает Disposeобъект, который инкапсулирует растровое изображение, любая ссылка на этот объект будет ссылкой на удаленный растровый объект. Если объект был удален преждевременно, в то время как другой код все еще ожидает его использования, класс точечного рисунка может гарантировать, что другой код завершится с ошибкой предсказуемым образом. Напротив, использование ссылки на освобожденную память является неопределенным поведением.
Суперкат
34

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

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

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

Теперь, как вы заявили, умные указатели могут использоваться для реализации формы сборки мусора.

Но ход мыслей идет следующим образом:

  1. Сборка мусора - это круто, так как это удобно, и мне нужно заботиться о меньшем количестве вещей
  2. Поэтому: я хочу сборку мусора на моем языке
  3. Теперь, как можно получить GC на моем языке?

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

Но в C ++ сборка мусора не предназначалась. Если мы выделяем некоторый указатель, int* p = new int;и он выходит из области видимости, pсам удаляется из стека, но никто не заботится о выделенной памяти.

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

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

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

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

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

Dario
источник
C # имеет форму детерминированного уничтожения через IDisposableи using. Но это требует немного усилий программиста, поэтому обычно используется только для очень скудных ресурсов, таких как дескрипторы подключения к базе данных.
JSB ձոգչ
7
@JSBangs: Точно. Подобно тому, как C ++ создает интеллектуальные указатели вокруг RAII для получения GC, C # идет другим путем и создает «интеллектуальные диспозиторы» вокруг GC для получения RAII;) На самом деле, это позор, что RAII настолько сложен в C #, что он хорош для исключений. безопасная обработка ресурсов. Например, F # пытается использовать более простой IDisposableсинтаксис, просто заменяя обычный let ident = valueна use ident = value...
Дарио,
@Dario: «C # идет другим путем и строит« умные диспозиторы »вокруг GC, чтобы получить RAII». RAII в C # usingвообще не имеет ничего общего с сборкой мусора, он просто вызывает функцию, когда переменная выходит из области видимости, как деструкторы в C ++.
Джон Харроп
1
@ Джон Харроп: Пожалуйста, что? Вы цитируете заявление о простых деструкторах C ++ без подсчета ссылок / умных указателей / сбора мусора.
Дарио
1
«Сборка мусора в основном означает, что ваши выделенные объекты автоматически освобождаются, когда на них больше нет ссылок. Точнее, они освобождаются, когда становятся недоступными для программы, так как иначе объекты с циклической ссылкой никогда не будут освобождены». ... Точнее было бы сказать, что они автоматически выпускаются в какой-то момент после , а не когда . Обратите внимание, что когда подразумевается, что рекламация происходит немедленно, тогда как на самом деле рекламация часто происходит намного позже.
Тодд Леман,
4

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

  1. Умные указатели не могут собирать циклический мусор; мусор может
  2. Умные указатели выполняют всю работу в моменты ссылок, разыменования и освобождения в потоке приложения; не нужно собирать мусор

Первый означает, что GC будет собирать мусор, а умные указатели - нет; если вы используете умные указатели, вам следует избегать создания такого рода мусора или быть готовым к его обработке вручную.

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

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

Однако в целях управления памятью я не вижу перспективы замены интеллектуальных указателей на сборку мусора. Они просто не так хороши в этом.

Том Андерсон
источник
6
@Tom: посмотрите на ответ Дарио для деталей о умных указателях. Что касается преимуществ интеллектуальных указателей, то детерминированное освобождение может быть огромным преимуществом при использовании для управления ресурсами (не только памятью). На самом деле, это оказалось настолько важным, что Microsoft представила usingблок в последующих версиях C #. Кроме того, недетерминированное поведение GC может быть запрещено в системах реального времени (именно поэтому GC там не используются). Кроме того, давайте не будем забывать, что GC настолько сложны в настройке, что большинство утечек памяти фактически неэффективны (например, Boehm ...).
Конрад Рудольф
6
Я считаю, что недетерминированность GC - это нечто вроде красной селедки - есть системы GC, которые подходят для использования в реальном времени (например, IBM Recycler), хотя те, которые вы видите в виртуальных машинах для настольных компьютеров и серверов, - нет. Кроме того, использование интеллектуальных указателей означает использование malloc / free, а традиционные реализации malloc недетерминированы из-за необходимости поиска в свободном списке. Движущиеся системы GC имеют более детерминированные времена распределения, чем системы malloc / free, хотя, конечно, меньше детерминированные времена освобождения.
Том Андерсон
3
Что касается сложности: да, сборщики мусора являются сложными, но я не знаю, что «на самом деле происходит утечка памяти, и они довольно неэффективны», и было бы интересно увидеть некоторые доказательства в противном случае. Boehm не является доказательством, потому что это очень примитивная реализация, и она построена для обслуживания языка C, где точный GC принципиально невозможен из-за отсутствия безопасности типов. Это смелое усилие, и то, что оно работает вообще, очень впечатляет, но вы не можете взять его за образец GC.
Том Андерсон
8
@ Джон: решительно не фигня. bugzilla.novell.com/show_bug.cgi?id=621899 или, в более общем плане: flyingfrogblog.blogspot.com/2009/01/… Это хорошо известно и является свойством всех консервативных сборщиков мусора .
Конрад Рудольф
3
«Стоимость выполнения современного GC меньше, чем у обычной системы malloc / free». Красная сельдь здесь. Это только потому, что традиционный malloc - ужасно неэффективный алгоритм. Современные распределители, которые используют несколько сегментов для блоков разных размеров, распределяются намного быстрее, гораздо менее подвержены фрагментации кучи и все же дают вам быстрое освобождение.
Мейсон Уилер
3

Термин «сборка мусора» подразумевает, что мусор нужно собирать. В C ++ умные указатели бывают разных типов, и самое главное - unique_ptr. Unique_ptr - это, по сути, единая структура владения и определения области видимости. В хорошо спроектированном фрагменте кода большинство выделенных в куче вещей обычно находятся за умными указателями unique_ptr, и право собственности на эти ресурсы всегда будет четко определено. Вряд ли есть какие-либо накладные расходы на unique_ptr, а unique_ptr устраняет большинство проблем ручного управления памятью, которые традиционно приводили людей к управляемым языкам. Теперь, когда большее количество ядер, работающих одновременно, становятся все более распространенными, принципы проектирования, которые заставляют код использовать уникальное и четко определенное владение в любой момент времени, становятся более важными для производительности.

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

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

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

user1703394
источник
1
Значит ли это, что Rustне нужно собирать мусор?
Гюльшан
1
@Gulshan Rust - один из немногих языков, который поддерживает безопасные уникальные указатели.
CodesInChaos
2

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

Проблема есть, если у вас есть круговые ссылки. То есть, A имеет ссылку на B, B имеет ссылку на C, а C имеет ссылку на A. Если вы используете умные указатели, то для освобождения памяти, связанной с A, B & C, вам нужно вручную получить там "разорвать" круговую ссылку (например, используя weak_ptrв C ++).

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

Таким образом, циклические ссылки больше не имеют значения - пока ни A, B, ни C не достижимы , память может быть восстановлена.

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

Конечно, в C ++ объем памяти, выделенной в куче, обычно меньше, чем у языка с интенсивными ссылками, такого как C # /. NET. Но на самом деле это не проблема сбора мусора против умных указателей.

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

Дин Хардинг
источник
2

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

Попробуйте в C ++ (без всякого GC) выделить большой набор объектов, выведите «hello» и удалите их. Вы будете удивлены, сколько времени потребуется, чтобы освободить объекты.

Кроме того, GNU libc предоставляет более эффективные инструменты для нераспределения памяти, см. Препятствия . Должен заметить, у меня нет опыта с препятствиями, я никогда не использовал их.

ern0
источник
В принципе, у вас есть точка зрения, но следует отметить, что эта проблема имеет очень простое решение: используйте распределитель пула или распределитель небольших объектов для объединения освобождений. Но это по общему признанию требует (немного) больше усилий, чем запуск GC в фоновом режиме.
Конрад Рудольф
Да, конечно, GC намного удобнее. (Специально для начинающих: нет проблем с владением, даже нет оператора удаления.)
ern0
3
@ ern0: нет. Весь смысл умных указателей (подсчета ссылок) заключается в том, что нет проблем с владением и нет оператора удаления.
Конрад Рудольф
3
@Jon: что, честно говоря, большую часть времени. Если вы добровольно разделяете состояние объекта между разными потоками, у вас будут совершенно разные проблемы. Я признаю, что многие программируют таким образом, но это является следствием плохих потоковых абстракций, которые существовали до недавнего времени, и это не хороший способ сделать многопоточность.
Конрад Рудольф
1
Распределение часто не выполняется "в фоновом режиме", а приостанавливает все потоки переднего плана. Сборка мусора в пакетном режиме, как правило, выигрывает в производительности, несмотря на приостановку потоков переднего плана, поскольку позволяет консолидировать неиспользуемое пространство. Можно разделить процессы сборки мусора и компактификации кучи, но - особенно в средах, в которых используются прямые ссылки, а не дескрипторы, - они оба, как правило, являются процессами "остановки мира", и зачастую их наиболее практично делать все вместе.
суперкат
2

Сборка мусора может быть более эффективной - в основном она «загружает» накладные расходы на управление памятью и выполняет все сразу. В целом, это приведет к уменьшению общей загрузки ЦП на перераспределение памяти, но это означает, что в какой-то момент у вас будет большой всплеск активности по выделению ресурсов. Если ГХ не спроектирован должным образом, это может стать видимым для пользователя как «пауза», в то время как ГХ пытается освободить память. Большинство современных ГХ очень хорошо держат это невидимым для пользователя, за исключением самых неблагоприятных условий.

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

Если вы делаете что-то, где важна отзывчивость, я бы посоветовал, чтобы умные указатели / подсчеты подсчитывали, чтобы вы точно знали, когда что-то происходит, чтобы вы могли знать при кодировании то, что может стать видимым для ваших пользователей. В настройках GC у вас есть только самый эфемерный контроль над сборщиком мусора, и вам просто нужно попытаться обойти это.

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

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

Майкл Кон
источник
1
«в какой-то момент у вас будет большой всплеск де-выделения». Беговая дорожка Пекаря - пример красиво возрастающего сборщика мусора. memorymanagement.org/glossary/t.html#treadmill
Джон Харроп
1

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

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

Sharptooth
источник
1

Это спектр .

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

«Я скажу вам, что делать, вы делаете это. Поверьте мне».

Сборка мусора является другим концом спектра. У вас очень мало контроля, но он позаботился о вас:

«Я скажу тебе, что я хочу, ты сделаешь это».

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

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

drjpizzle
источник
0

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

Все это, помимо сбора мусора, ссылок на данные, которые могли быть перемещены, сжатия кучи и т. Д. И т. Д., Выполняет работу в рамках ограничений, указанных в приведенной выше парадигме «блок памяти с указателем адреса». То же самое с умными указателями - вы все равно должны заставить код работать на реальном оборудовании.


источник