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

Когда вы не захотите использовать сбор мусора?

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

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

Вам приходилось делать это?

Пожалуйста, приложите убедительные примеры.

4b9b3361

Ответ 1

Я могу думать о нескольких:

Детерминированное освобождение/очистка

Системы реального времени

Не отказываться от половины времени памяти или процессора - в зависимости от алгоритма

Более быстрое выделение памяти /dealloc и распределение приложений, освобождение и управление памятью. В основном пишу собственные материалы для памяти - обычно для приложений с высокой чувствительностью. Это можно сделать там, где поведение приложения достаточно хорошо понято. Для GC общего назначения (например, для Java и С#) это невозможно.

ИЗМЕНИТЬ

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

Ответ 2

Распределение памяти? Нет, я думаю, что GC лучше в этом, чем я.

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

Ответ 3

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

Я также пишу много инструментов поддержки на базе ПК и с радостью использую GC, где он доступен и достаточно быстро, а это значит, что мне не нужно использовать pedant:: std::string.

Я пишу много кода сжатия и шифрования, и производительность GC обычно недостаточно хороша, если я действительно не сгибаю реализацию. GC также требует, чтобы вы были очень осторожны с трюками сглаживания адресов. Обычно я пишу код, чувствительный к производительности, в C и вызываю его из передних концов Python/С#.

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

Если я что-то создаю в MSVС++, я никогда не использую сбор мусора. Отчасти потому, что он нестандартен, но также потому, что я вырос без GC на С++ и автоматически проектирую в безопасной мелиорации памяти. Сказав это, я считаю, что С++ - это мерзость, которая не может обеспечить прозрачность трансляции и предсказуемость C или безопасность в области охвата памяти (среди прочего) более поздних языков OO.

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

Два слова: Пространство >

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

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

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

Ответ 8

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

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

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

Имея 16 гигов барана вместо 8, вероятно, тоже устранил бы проблему. В общем, мне просто нужно было сделать некоторую дополнительную настройку, чтобы заставить ее работать, и поскольку я не могу отключить gc в java, это был мой единственный вариант.

Я подозреваю, что новый Java 7-го уровня исправил бы мою проблему.

Ответ 9

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

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

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

Ответ 10

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

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

Ответ 11

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

Потенциально, несколько возможных причин:

  • Задержка программы из-за сборщика мусора недопустимо высока.

  • Задержка перед рециркуляцией является неприемлемо длинной, например. выделение большого массива на .NET помещает его в кучу больших объектов (LOH), который редко собирается, поэтому он некоторое время будет нависнуть после того, как он станет недоступным.

  • Другие накладные расходы, связанные с сбором мусора, недопустимо высоки, например. барьер записи.

  • Характеристики сборщика мусора неприемлемы, например. удвоение массивов на фрагментах .NET - большая куча объектов (LOH), вызывающая нехватку памяти при исчерпании 32-разрядного адресного пространства, хотя теоретически много свободного места. В OCaml (и, возможно, большинстве языков GC'd) функции с глубокими стеками потоков работают асимптотически медленнее. Также в OCaml потоки не могут запускаться параллельно глобальной блокировкой на GC, поэтому (теоретически) parallelism может быть достигнуто путем перехода на C и использования ручного управления памятью.

Вам приходилось делать это?

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

Ближайшая к сбору мусора собирает сам язык OCaml, потому что его GC препятствует parallelism. Тем не менее, я закончил переход на F #, который является языком .NET, и, следовательно, наследует CLR превосходный многоядерный GC.

Ответ 12

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

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

Я никогда не нашел причины делать # 1, но # 2 - это тот, который приходит иногда. Многие сборщики мусора предлагают механизмы для финализации, который является действием, которое вы связываете с объектом, и система запускает это действие до того, как объект будет исправлен. Но часто система не дает никаких гарантий относительно того, действительно ли выполняются финализаторы, поэтому окончательная доработка может быть ограниченной полезностью.

Главное, что я делаю на собранном мусором языке, - это следить за количеством распределений на единицу другой работы. Распределение обычно является узким местом производительности, особенно в системах Java или .NET. Это меньше проблема в таких языках, как ML, Haskell или LISP, которые, как правило, разработаны с идеей о том, что программа будет выделяться как сумасшедшая.


EDIT: более длинный ответ на комментарий.

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

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

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

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

Ответ 13

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

Например, Big Bad находится впереди из вас, и вы до десяти человек. Вы решили бежать к Квадрату Урон от повреждения. Как только вы поднимете бонусы, вы готовитесь к повернитесь к своему врагу, чтобы стрелять ваше самое сильное оружие.

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

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

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

Изменить: после прочтения других комментариев я понял, что встроенные системы и упрощение пространства (комментарии Bill and tinkertim, соответственно) также являются вескими причинами, чтобы отключить сборщик мусора

Ответ 14

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

Используйте контекст, чтобы определить необходимость:

1.

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

2.

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

3.

  • Истощение ресурсов может быть вызвано сбором мусора
  • У вас больше процессора и памяти, чем вы можете управлять в своей голове?

4.

  • Сбор мусора не может адресовать файлы и сокеты
  • У вас есть I/O в качестве основной проблемы?

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

Ссылки