Сбор программ по сбору мусора или без мусора

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

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

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

Ответы

Ответ 1

  • Утешение вещей, которые вам нужны

  • Не освобождать вещи, которые вам больше не нужны (потому что вы не отслеживаете распределения/использование/освобождает хорошо)

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

  • Отмена выделения того, что вы уже освободили

  • Отмена выделения чего-то, что не существует (нулевой указатель)

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

Ответ 2

ИМО, у сборных мусора есть дополнительные проблемы для тех, кто не связан с мусором. Для каждой проблемы существует ошибка, не относящаяся к GC-характеристике, и ошибка GC-характеристики - ответственность программиста, не относящегося к GC, и ответственность программиста GC.

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

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

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

Коллекция параллельного цикла в подсчитанных системах

Конечно, это обычно не делается - отчасти потому, что вы можете просто использовать язык GC, но также частично IMO, потому что он нарушит ключевые соглашения на С++. Вы видите, что много кода на С++, включая стандартную библиотеку, в значительной степени зависит от соглашения о распределении ресурсов (RAII) и полагается на надежные и своевременные вызовы деструктора. В любом GC, который справляется с циклами, вы просто не можете этого сделать. При разрыве цикла мусора вы не можете знать, какой деструктор вызывать первым без каких-либо проблем с зависимостями - возможно, это даже не возможно, так как может быть больше циклических зависимостей, чем только ссылки на память. Решение - в Java и т.д. Нет гарантии, что будут вызываться финализаторы. Сбор мусора собирает только один особый вид мусора - память. Все остальные ресурсы должны быть очищены вручную, так как они были бы в Pascal или C и без преимущества надежных деструкторов стиля С++.

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

[ EDIT - бывают случаи, когда Java, С# и т.д., очевидно, делают надежную (если не обязательно своевременную) очистку, и файлы являются примером этого. Это объекты, в которых ссылочные циклы не могут произойти - либо потому, что (1) они вообще не содержат ссылок, (2) существует некоторое статическое доказательство того, что содержащиеся в нем ссылки не могут прямо или косвенно возвращаться к другому объекту того же типа или (3) логика времени выполнения гарантирует, что в то время как цепочки/деревья/всевозможные возможные циклы не являются. Случаи (1) и (2) чрезвычайно распространены для объектов управления ресурсами, в отличие от узлов структуры данных - возможно, универсальных. Однако сам компилятор не может разумно гарантировать (3). Поэтому, хотя разработчики стандартных библиотек, которые пишут наиболее важные классы ресурсов, могут обеспечить надежную очистку для них, общее правило по-прежнему заключается в том, что надежная очистка ресурсов без памяти не может быть гарантирована для GC, и это может повлиять на ресурсы, определенные приложением. ]

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

Хороший программист должен пройти мимо BS-BS-BS и научиться обращаться с ними.

Ответ 3

Ну, ошибки, которые вы можете сделать, следующие:

  • Не освобождать вещи, которые вам не нужны.
  • Расселение вещей, которые вам нужны.

Существуют и другие ошибки, которые вы можете сделать, но те, которые относятся конкретно к сборке мусора.

Ответ 4

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

Ответ 5

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

Кроме того, в С++ вы должны быть осторожны с микшированием new[]/delete и new/delete[].

Например, управление памятью - это то, что требует от программиста точно знать, почему

const char *getstr() { return "Hello, world!" }

просто отлично, но

const char *getstr() {
    char x[BUF_SIZE];
    fgets(x, BUF_SIZE, stdin);
    return x;
}

- очень плохая вещь.

Ответ 6

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

Ответ 7

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

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

Многие интеллектуальные указатели могут создавать утечки памяти с помощью:

  • Циклы или круговая ссылка (A указывает на B, B указывает на A).
  • ошибки в реализации интеллектуального указателя (редко в зрелых библиотеках, таких как Boost)
  • смешивание исходных указателей с интеллектуальными указателями
  • безопасность потока
  • неправильно привязан или отсоединен от необработанного указателя

Эти проблемы не должны встречаться в полностью интегрированных средах GC.

Ответ 8

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

Ответ 9

Обычно языки с Garbage Collection ограничивают доступ программиста к памяти и полагаются на модель памяти, в которой объекты содержат:

  • счетчики ссылок - GC использует это, чтобы знать, когда объект не используется, и
  • информация о типе и размере - для устранения переполнения буфера (и уменьшения количества других ошибок).

По сравнению с языком, отличным от GC, существуют два класса ошибок, которые уменьшаются/устраняются моделью и ограниченным доступом:

  • Ошибки модели памяти, такие как:

    • утечки памяти (отказ при освобождении после завершения),
    • освобождение памяти более одного раза,
    • освобождение памяти, которая не была выделена (например, глобальные или стековые переменные),
  • Ошибки указателя, такие как:

    • Неинициализированный указатель, с "оставшимися" битами от предыдущего использования,
    • Доступ, особенно запись в память после освобождения (противный!)
    • Ошибки переполнения буфера,
    • Использование памяти как неправильного типа (путем литья).

Есть больше, но это большие.

Ответ 10

Пожалуйста, не сравнивайте языки OO (Java, С#) с языками, отличными от OO (C), когда речь идет об сборке мусора. Языки OO (в основном) позволяют вам внедрять GC (см. Комментарий о интеллектуальных указателях). Да, они не легкие, но они помогают много, и они детерминированы.

Также, как GC-языки сравниваются с не-GC-языками при рассмотрении ресурсов, отличных от памяти, например. файлы, сетевые подключения, соединения с БД и т.д.

Я думаю, что ответ на этот вопрос, оставленный читателю, тоже прольет свет.