C ++ delete vs Java GC

Сбор мусора Java заботится о мертвых объектах в куче, но иногда замораживает мир. В C ++ я должен вызвать delete, чтобы уничтожить созданный объект в конце жизненного цикла.

Этот delete кажется очень низкой ценой для оплаты за незамерзающую среду. Размещение всех соответствующих ключевых слов delete - это механическая задача. Можно написать скрипт, который будет перемещаться по коду и удалять место, если новые ветви не используют данный объект.

Итак, каковы плюсы и минусы построения Java в vs C ++ diy модели сбора мусора.


Я не хочу запускать поток C ++ vs Java. Мой вопрос другой.
Вся эта вещь GC - это сводится к тому, чтобы «просто быть аккуратным, не забывайте удалять объекты, которые вы создали, и вам не понадобится какой-либо выделенный GC? Или это больше похоже на то, что« утилизация объектов на C ++ действительно сложна - I потратьте 20% своего времени на это, и все же утечка памяти - обычное место "?

6 голосов | спросил sixtytrees 16 J0000006Europe/Moscow 2016, 21:54:41

6 ответов


14

Жизненный цикл объекта C ++

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

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

К счастью, в современном C ++ (aka C ++ 11 и более поздних) у вас есть интеллектуальные указатели, например, shared_ptr . Они ссылаются на отсчет созданного объекта очень эффективным образом, немного похоже на сборщик мусора, который будет делать на Java. И как только объект больше не ссылается, последний активный shared_ptr удаляет объект для вас. Автоматически. Как сборщик мусора, но один объект за раз и без задержки (Ok: вам нужна дополнительная осторожность и weak_ptr, чтобы справиться с круговыми ссылками) ,

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

Жизненный цикл объекта Java

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

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

Это прекрасно, если смотреть на объекты только с точки зрения памяти. За исключением замораживания, но это не смертельный исход (люди работают над этим). Я не эксперт по Java, но я думаю, что отсроченное уничтожение затрудняет идентификацию утечки в java из-за ссылок случайно сохраняются, несмотря на то, что объекты больше не нужны (т. е. вы не можете реально контролировать удаление объектов).

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

Заключение: GC решает проблему управления памятью. Но это не относится к управлению другими системными ресурсами. Отсутствие удаления «точно в срок» может сделать управление ресурсами очень сложным.

Удаление, сбор мусора и RAII

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

ответил Christophe 17 J0000006Europe/Moscow 2016, 02:46:42
4
  

Это удаление кажется очень низкой ценой для оплаты за незамерзающую среду. Размещение всех соответствующих ключевых слов удаления - это механическая задача. Можно написать скрипт, который будет перемещаться по коду и удалять место, если новые ветви не используют данный объект.

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

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

ответил gnasher729 16 J0000006Europe/Moscow 2016, 22:22:19
4

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

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

Таким образом, в C ++ удаление объектов происходит быстро, но их создание может быть медленным. В Java создание объектов занимает совсем немного времени, но вам нужно некоторое время заниматься некоторой работой.

ответил kamilk 17 J0000006Europe/Moscow 2016, 03:27:09
4

Если вы пишете правильный код C ++ с RAII, вы обычно не пишете никаких новых или удаляете. Единственный «новый», который вы пишете, находится внутри общих указателей, поэтому вам действительно не нужно использовать «delete».

ответил Nikko 17 J0000006Europe/Moscow 2016, 17:00:29
2

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

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

В Java, когда вы выталкиваете что-то из стека, возвращаемое значение возвращается, поэтому вы получаете такой код:

WhateverType value = myStack.Pop();

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

WhateverType value = myStack.top();
myStack.pop();

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

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

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

Что касается простого сценария для вставки delete, где необходимо: если вы можете статически определять, когда удалять элементы на основе структуры Исходный код, вероятно, не должен был использовать new и delete в первую очередь.

Позвольте мне привести пример программы, для которой это почти наверняка будет невозможно: система для размещения, отслеживания, биллинга (и т. д.) телефонных звонков. Когда вы набираете свой телефон, он создает объект «вызов». Объект вызова отслеживает, кто вы звонили, как долго вы разговариваете с ними и т. Д., Чтобы добавить соответствующие записи в журналы выставления счетов. Объект вызова контролирует состояние аппаратного обеспечения, поэтому, когда вы повесите трубку, он уничтожает себя (используя широко обсуждаемый delete this;). Только, это не так уж и тривиально, как «когда вы вешаете». Например, вы можете инициировать конференц-связь, подключить двух человек и повесить трубку - но вызов продолжается между этими двумя сторонами даже после того, как вы повесили трубку (но биллинг может измениться).

ответил Jerry Coffin 20 J0000006Europe/Moscow 2016, 19:00:21
2

Что-то, о чем я не думаю, было упомянуто здесь, так это то, что есть эффективность, полученная от сбора мусора. В наиболее часто используемых сборниках Java основным местом размещения объектов является область, зарезервированная для копировального коллектора. Когда все начинается, это пространство пусто. По мере создания объектов они выделяются рядом друг с другом в большом открытом пространстве до тех пор, пока они не смогут выделить один из оставшихся смежных пространств. GC запускается и ищет любые объекты в этом пространстве, которые не мертвы. Он копирует живые объекты в другую область и объединяет их (т. Е. Не фрагментирует.) Старое пространство считается чистым. Затем он продолжает распределять объекты плотно и повторяет этот процесс по мере необходимости.

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

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

Этот вид сбора и распределения very быстро. С точки зрения общей пропускной способности трудно выполнить многие сценарии. Проблема в том, что некоторые объекты будут жить дольше, чем вы хотите их копировать, и в конечном итоге это означает, что коллекционеру может потребоваться пауза в течение значительного времени каждый раз в то время, и когда это произойдет, может быть непредсказуемым. В зависимости от продолжительности паузы и вида приложения это может быть или не быть проблемой. Существует как минимум беспроигрышный сборщик. Я ожидаю, что есть некоторый компромисс с более низкой эффективностью, чтобы получить беззаботный характер, но один из людей, которые основали эту компанию (Гил Тене), является экспертом-uber в GC, и его презентации - отличный источник информации о GC.

ответил JimmyJames 20 J0000006Europe/Moscow 2016, 19:40:39

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132