Подтвердить что ты не робот

Зачем использовать сборщик мусора?

Возможный дубликат:
Сбор мусора в С++ — почему?

Привет, я прочитал несколько статей о сборщиках мусора, и все же есть одна вещь, которую я просто не понимаю - зачем использовать сбор мусора?

Я попытаюсь объяснить свои мысли:

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

Итак, зачем использовать GC, когда все, что вам нужно сделать, на самом деле просто разумно с распределением/освобождением памяти? Или я чего-то не хватает? Спасибо.

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

Потому что мы недостаточно умны.

Ответ 5

Когда я пишу программы, мне нравится концентрироваться на своей проблемной области, а не на мелочах деталей, связанных с несобственной реализацией. Например, если я пишу, скажем, веб-сервер, мой проблемный домен - это сетевые подключения, протоколы, передача/прием данных и т.д., А не распределение памяти и освобождение. Если я пишу видеоигру, мой проблемный домен - это графическая производительность и, возможно, ИИ и снова не распределение памяти и освобождение.

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

Кроме того, ваше "все, что вам нужно сделать, это просто разумно с распределением памяти/освобождением", бит служит только для выделения двух возможностей (о которых я могу думать, во всяком случае):

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

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

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

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

Ответ 6

Рассмотрим случай, когда конкретный указатель используется двумя отдельными подсистемами. Одна подсистема может быть выполнена с переменной, и программист может подумать: "Я покончил с этим, я просто продолжу и освобожу его", совершенно не осознавая, что другой подсистеме все еще нужен доступ к ней. Девелопер думает: "Я не уверен, есть ли другая подсистема, которая может понадобиться" (даже если это не так) приводит к утечкам памяти. Такая сложная ситуация возникает в сложных системах.

Ответ 7

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

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

Ответ 8

Это механизм anti-dumb-programmer. И поверьте мне, когда код становится очень сложным, когда мы думаем о динамически распределенной памяти, мы все равно немой.

В моем коротком опыте программиста я потратил (кумулятивные) дни, пытаясь понять, почему valgrind (или другие подобные инструменты) сообщают о утечке памяти, когда все было так "мудро закодировано".

Ответ 9

В наши дни большинство людей, использующих сборщик мусора, делают это внутри управляемой среды (например, виртуальной машины Java или среды .NET Common Language Runtime). Эти управляемые среды добавляют дополнительную морщину: они ограничивают способность принимать указатели на вещи. Например, в среде CLR существует понятие указателя (которое вы можете использовать с помощью управляемого IntPtr или неуправляемого блока кода unsafe), но существуют ограниченные условия, в которых вы можете использовать их. В большинстве случаев вам нужно "привязать" соответствующие объекты в памяти, чтобы GC не двигал их, пока вы работаете с их указателями.

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

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

Наконец, сбор мусора становится действительно необходимым при работе с языками функционального программирования (или программированием в функциональных стилях). Фактически, самый первый сборщик мусора был изобретен Маккарти в 1959 году как часть развития языка Lisp. Причина двоякая: во-первых, функциональное программирование стимулирует неизменные структуры данных, которые легче собрать, а во-вторых, в чисто функциональном программировании нет функции распределения; память всегда получает выделение как "стек" (функции locals), а затем переходит в "кучу", если она захватывается closure. (Это грубое упрощение, но служит для иллюстрации этой точки.)

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

Ответ 10

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

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

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

Ответ 11

Итак, если вы пишете программу на языке C, вы знаете, что вам нужна некоторая часть памяти, поэтому, если вы этого не сделаете, вы можете просто ее уничтожить.

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

for (x in ComputeBigList()) ...

становится этим

var xs = ComputeBigList();

try {
   for(x in xs) ...
} finally {
   FreeMemory(xs);
}

Отсутствие сборщика мусора требовало, чтобы мы назвали результат ComputeBigList, сохранили его в переменной и затем добавили инструкцию delete, заключенную в finally, чтобы убедиться, что она действительно удалена.

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

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

Ответ 12

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

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

Другой способ избежать сбора мусора - использовать язык, который не отделяет ссылку от содержимого. В этом случае реальная утечка памяти даже невозможна. (Но, конечно, по-прежнему можно использовать слишком много памяти.) ИМХО, языки высокого уровня не должны путать с "указателями" (адресными переменными) вообще.

Ответ 13

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

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

  • проблема проста (например, кратковременное приложение командной строки), и программист достаточно дисциплинирован;
  • программист Дональд Кнут.

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

Ответ 14

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

Ответ 15

Сбор мусора может быть более эффективным.

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

В С++ вы можете безопасно и чисто работать с памятью во многих ситуациях без сборщика мусора, используя интеллектуальные указатели и строго придерживаясь условностей. Но (1) это не работает во всех ситуациях, даже с shared_ptr и weak_ptr, и (2) подсчет ссылок требует координации по потокам, которая имеет ограничение производительности.

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

Ответ 16

вы знаете, что вам нужна часть памяти, поэтому, если вы этого не сделаете, вы можете просто уничтожить ее.

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

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

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

Ответ 17

Итак, зачем использовать GC, когда все, что вам нужно сделать, на самом деле просто разумно с распределением/освобождением памяти?

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

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

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

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

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

Ответ 18

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

С Garbage Collection, однако вам не нужно заботиться о памяти и больше сосредоточиться на остальной части вашей программы, таким образом, возможно, развивайте "быстрее"

Ответ 19

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

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

Ответ 20

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

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

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

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

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

Ответ 21

Вам может потребоваться освободить ресурсы Interop как можно скорее (заблокированный файл). Gc.Collect может обеспечить освобождение COM-объектов (если не указано).

Если вы выполняете PrintPreview, для каждой страницы требуется 2 дескриптора Gdi (изображение + метафайл). Эти ресурсы не выпущены PrintDocument или PrintControler, ждут GC.

Я тестировал в интерактивной программе использование Gc.Collect, когда пользователь возвращается в главное меню. При этой операции сообщаемая память для диспетчера задач составляет около 50%.

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

Ответ 22

Управление памятью - это проблема с внедрением, которая не связана с целью программы.

по цели программы я имею в виду такие вещи, как бизнес-логика.

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