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

Почему free() не разрешено на собраниях, связанных с мусором?

Я читал запись С# в Википедии и наткнулся на:

Управляемая память не может быть явно освобождена; вместо этого автоматически собирается мусор.

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

4b9b3361

Ответ 1

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

Теперь, если распределитель памяти позволяет использовать ручную free() и использует сбор мусора, он должен гарантировать, что в памяти, на которую вы free() 'd не ссылаетесь никем; другими словами, ссылка, которую вы передаете на free(), является единственной ссылкой на эту память. Большую часть времени это слишком дорого стоить при произвольном вызове free(), поэтому большинство распределителей памяти, которые используют сбор мусора, не позволяют это.

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

Ответ 2

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

Среди предотвращенных проблем есть

  • Двойной free() s
  • Вызов free() указателя на память, который у вас нет, что приводит к незаконному доступу в других местах
  • Вызов free() указателя, который не был возвращаемым значением функции выделения, например, для адреса адреса какого-либо объекта в стеке или в середине массива или другого выделения.
  • Вызов указателя на память, который уже был free() d

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

Ответ 3

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

Когда среда выполнения ссылается на отслеживание counting для вас, она знает, какие указатели могут быть освобождены безопасно, а какие нет, поэтому позволить GC решить, какая память может быть освобождена, избегает класс дыр уродливого ошибок. Можно подумать о реализации во время выполнения как с GC, так и free, где явный вызов free для одного блока памяти может быть намного быстрее, чем запуск полного GC.Collect (но не ожидайте освобождения всех возможных блоков памяти "вручную", чтобы быть быстрее, чем GC). Но я думаю, что дизайнеры С#, CLI (и другие языки с сборщиками мусора, такие как Java) решили поддержать уверенность и безопасность в скорости здесь.

Ответ 4

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

Ответ 5

Я не могу сказать, что это ответ, но тот, который приходит на ум, состоит в том, что если вы можете free, вы можете случайно удвоить free указатель/ссылку или еще хуже, используйте один после бесплатного. Что поражает основной смысл использования таких языков, как С#/java/etc.

Конечно, одним из возможных решений для этого было бы заставить ваш free принять аргумент по ссылке и установить его после null после освобождения. Но тогда, если они передают r-value следующим образом: free(whatever()). Я предполагаю, что у вас может быть перегрузка для версий r-value, но даже не знаю, поддерживает ли С# такую ​​вещь: -P.

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

Ответ 6

Если вы находитесь в ситуации, когда вы "не хотите полагаться на GC, являющийся умным", то, скорее всего, вы выбрали фреймворк для своей задачи неправильно. В .net вы можете немного манипулировать GC (http://msdn.microsoft.com/library/system.gc.aspx), в Java не уверен.

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

Ответ 7

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

Мне советовали один раз использовать следующие 2 строки сторонним поставщиком для решения проблемы с сборкой мусора с помощью DLL или COM-объекта или некоторых таких:

// Force garbage collection (cleanup event objects from previous run.)
GC.Collect();         // Force an immediate garbage collection of all generations
GC.GetTotalMemory(true);

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

Ответ 8

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

Я хотел бы добавить трюк, который я стараюсь иметь в виду при программировании на языках GC'd. Правило таково: "Важно как можно скорее сбросить указатели". Отбрасывая указатели, я имею в виду, что я больше не указываю на объекты, которые я больше не буду использовать. Например, это можно сделать на некоторых языках, установив переменную в Null. Это можно увидеть как подсказку сборщику мусора, чтобы было хорошо собрать этот объект, если нет других указателей на него.

Ответ 9

Почему вы хотите использовать free()? Предположим, у вас есть большая часть памяти, которую вы хотите освободить.

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

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

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

Ответ 10

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

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

Существуют две основные причины, по которым free отсутствует на собраниях мусора:

  • Безопасность памяти.
  • Нет указателей.

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

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

Поэтому есть веские причины не иметь free, когда у вас есть GC.

Ответ 11

Ручное управление разрешено. Например, в Ruby, вызывающем GC.start, освобождается все, что может быть освобождено, хотя вы не можете освобождать вещи по отдельности.