Лекция
Это продолжение увлекательной статьи про сборка мусора.
...
памяти из-за списка / дополнительного бита. Это можно несколько смягчить, если сборщик также обрабатывает выделение, с тех пор он потенциально может использовать неиспользуемые биты в структурах данных распределения. Или эта «скрытая память» может быть устранена с помощьюТегированный указатель , обменивающий стоимость памяти на процессорное время. Однако отметка и очистка - единственная стратегия, которая в первую очередь легко взаимодействует с внешними распределителями.
Знак и не подметатьСборщик мусора, как и mark-and-sweep, сохраняет бит с каждым объектом, чтобы записать, белый он или черный; серый набор хранится как отдельный список или с использованием другого бита. Здесь есть два ключевых отличия. Во-первых, черное и белое означают разные вещи, чем в сборщике отметок и подметаний. В коллекторе «пометить и не подметать» все доступные объекты всегда черные. В момент размещения объект помечается черным, и он останется черным, даже если станет недоступным. Белый объект - это неиспользуемая память и может быть выделена. Во-вторых, может измениться интерпретация битов черного / белого. Первоначально бит черного / белого может иметь значение (0 = белый, 1 = черный). Если при операции выделения памяти не удается найти доступную (белую) память, это означает, что все объекты помечаются как использованные (черным). Затем значение бит черного / белого инвертируется (например, 0 = черный, 1 = белый). Все становится белым. Это на мгновение нарушает инвариант, согласно которому достижимые объекты являются черными, но сразу же следует полная фаза маркировки, чтобы снова пометить их черным. Как только это будет сделано, вся недостижимая память станет белой. Никакой фазы "развертки" не требуется.
Знак и не подметать стратегия требует сотрудничества между распределителем и коллектором, но невероятно пространство эффективно , так как она требует только одного бита , выделенного указателем (который большинство алгоритмов распределения требуется в любом случае). Однако этот положительный момент несколько смягчается, поскольку большую часть времени большие части памяти ошибочно помечаются черным (используется), что затрудняет возврат ресурсов системе (для использования другими распределителями, потоками или процессами) во время низкое использование памяти.
Таким образом, стратегию « метить и не проводить» можно рассматривать как компромисс между положительными и отрицательными сторонами « метки и развертки» и стратегиями « стоп и копирование» .
Эмпирически было замечено, что во многих программах самые недавно созданные объекты также являются теми, которые, скорее всего, быстро станут недоступными (это известно как детская смертность или гипотеза поколений.). Сборщик поколений (также известный как эфемерный сборщик мусора) делит объекты на поколения и в большинстве циклов помещает только объекты подмножества поколений в начальный белый (осужденный) набор. Кроме того, система времени выполнения поддерживает информацию о том, когда ссылки перекрестные поколения, наблюдая за созданием и перезаписью ссылок. Когда сборщик мусора запускается, он может использовать эти знания, чтобы доказать, что некоторые объекты в начальном белом наборе недоступны, без необходимости обхода всего ссылочного дерева. Если гипотеза поколений верна, это приводит к гораздо более быстрым циклам сбора, при этом возвращая большинство недостижимых объектов.
Чтобы реализовать эту концепцию, многие сборщики мусора поколения используют отдельные области памяти для разного возраста объектов. Когда область становится заполненной, объекты в ней отслеживаются с использованием ссылок из более старшего поколения (ов) в качестве корней. Обычно это приводит к тому, что большинство объектов в поколении собирается (по гипотезе), оставляя его для использования для выделения новых объектов. Когда коллекция не собирает много объектов (гипотеза не выполняется, например, потому что программа вычислила большую коллекцию новых объектов, которую она хочет сохранить), некоторые или все уцелевшие объекты, на которые ссылаются из более старой памяти регионы перемещаются в следующий по высоте регион, и затем весь регион может быть перезаписан новыми объектами. Этот метод позволяет очень быстро наращивать сборку мусора,
УнгарКлассическое поколение мусорщиков насчитывает два поколения. Он разделяет самое молодое поколение, называемое «новым пространством», на большой «рай», в котором создаются новые объекты, и два меньших «пространства выживших», пространство прошлого и пространство будущих выживших. Объекты в старом поколении, которые могут ссылаться на объекты в новом пространстве, хранятся в «запоминаемом наборе». При каждой уборке объекты в новом пространстве отслеживаются от корней в запомненном наборе и копируются в пространство будущего выжившего. Если пространство будущего выжившего заполняется, объекты, которые не подходят, перемещаются в старое пространство, процесс, называемый «владение». В конце уборки некоторые объекты находятся в пространстве будущего выжившего, а пространство Эдема и прошлого выжившего пусто. Затем пространство будущего выжившего и пространство прошлого выжившего меняются местами, и программа продолжается, выделяя объекты в eden. В оригинальной системе Ангара Эдем в 5 раз больше, чем место каждого выжившего.
Сборка мусора поколений - это эвристический подход, и некоторые недостижимые объекты не могут быть восстановлены в каждом цикле. Поэтому иногда может потребоваться выполнить полную отметку и очистку или копирование сборки мусора, чтобы освободить все доступное пространство. Фактически, системы времени выполнения для современных языков программирования (таких как Java и .NET Framework ) обычно используют некий гибрид различных стратегий, которые были описаны до сих пор; например, большинство циклов сбора могут рассматривать только несколько поколений, в то время как иногда выполняется метка и очистка, и еще реже выполняется полное копирование для борьбы с фрагментацией. Термины «малый цикл» и «большой цикл» иногда используются для описания этих различных уровней агрессии коллекционера.
Простые сборщики мусора «остановить мир» полностью останавливают выполнение программы для запуска цикла сбора, тем самым гарантируя, что новые объекты не будут выделены, и объекты не станут внезапно недоступными во время работы сборщика.
Это имеет очевидный недостаток, заключающийся в том, что программа не может выполнять полезную работу во время выполнения цикла сбора (иногда это называется «неловкой паузой»). Поэтому сборка мусора Stop-the-world в основном подходит для неинтерактивных программ. Его преимущество в том, что его проще реализовать и быстрее, чем инкрементная сборка мусора.
Инкрементные и параллельные сборщики мусора призваны уменьшить это нарушение, чередуя их работу с деятельностью основной программы. Инкрементные сборщики мусора выполняют цикл сборки мусора дискретными фазами, при этом выполнение программы разрешено между каждой фазой (а иногда и на некоторых фазах). Параллельные сборщики мусора вообще не останавливают выполнение программы, за исключением, возможно, кратковременного сканирования стека выполнения программы. Однако сумма инкрементных фаз занимает больше времени, чем один проход пакетной сборки мусора, поэтому эти сборщики мусора могут дать более низкую общую пропускную способность.
Эти методы требуют тщательного проектирования, чтобы гарантировать, что основная программа не мешает сборщику мусора и наоборот; например, когда программе необходимо выделить новый объект, системе времени выполнения может потребоваться либо приостановить его до завершения цикла сбора, либо каким-то образом уведомить сборщик мусора о том, что существует новый достижимый объект.
Некоторые сборщики могут правильно идентифицировать все указатели (ссылки) в объекте; их называют точными (также точными или точными ) коллекционерами, а наоборот - консервативными или частично консервативными коллекционерами. Консервативные сборщики предполагают, что любой битовый шаблон в памяти может быть указателем, если, интерпретируемый как указатель, он будет указывать на выделенный объект. Консервативные сборщики могут давать ложные срабатывания, когда неиспользуемая память не освобождается из-за неправильной идентификации указателя. На практике это не всегда проблема, если программа не обрабатывает большое количество данных, которые легко могут быть ошибочно идентифицированы как указатель. Ложные срабатывания обычно менее проблематичны на 64-битнойсистемы, чем в 32-битных системах, потому что диапазон допустимых адресов памяти, как правило, составляет крошечную часть диапазона 64-битных значений. Таким образом, произвольный 64-битный шаблон вряд ли имитирует действительный указатель. Ложноотрицательный результат также может произойти, если указатели «скрыты», например, при использовании связанного списка XOR . Практичность точного сборщика обычно зависит от свойств безопасности типа рассматриваемого языка программирования. Примером, для которого может потребоваться консервативный сборщик мусора, является язык C , который позволяет типизированным (непустым) указателям преобразовывать тип в нетипизированные (пустые) указатели и наоборот.
Связанная проблема касается внутренних указателей или указателей на поля внутри объекта. Если семантика языка допускает внутренние указатели, тогда может быть много разных адресов, которые могут ссылаться на части одного и того же объекта, что усложняет определение того, является ли объект мусором или нет. Примером этого является язык C ++ , в котором множественное наследование может привести к тому, что указатели на базовые объекты будут иметь разные адреса. В сильно оптимизированной программе соответствующий указатель на сам объект мог быть перезаписан в его регистре, поэтому такие внутренние указатели необходимо сканировать.
Чтобы программа могла использовать сборку мусора, необходимо выполнение ряда условий, относящихся к языку, среде исполнения и самой решаемой задаче.
Необходимость среды исполнения со сборщиком мусора
Естественно, для сборки мусора необходима динамическая среда, поддерживающая исполнение программы, и наличие в этой среде сборщика мусора. У интерпретируемых языков или языков, компилируемых в байт-код виртуальной машины сборщик мусора может быть включен в код интерпретатора языка или байт-кода, но для компилируемых в объектный код языков сборщик мусора вынужденно становится частью системной библиотеки, которая компонуется (статически или динамически) с программным кодом при создании исполняемого файла, увеличивая размер программы и время ее загрузки.
Поддержка со стороны языка программирования
Сборщик мусора может нормально функционировать только тогда, когда он может точно отследить все ссылки на все созданные объекты. Очевидно, если язык допускает преобразование ссылок (указателей) в другие типы данных (целые числа, массивы байтов и так далее), такой как Си/Си++, отследить использование таких преобразованных ссылок становится невозможно, и сборка мусора становится бессмысленной — она не защищает от «повисания» ссылок и утечек памяти. Поэтому языки, ориентированные на использование сборки мусора, обычно существенно ограничивают свободу использования указателей, адресной арифметики, преобразований типов указателей к другим типам данных. В части из них вообще нет типа данных «указатель», в части он есть, но не допускает ни преобразований типа, ни изменения.
Техническая допустимость кратковременных замедлений в работе программ
Сборка мусора выполняется периодически, как правило, в заранее неизвестные моменты времени. Если приостановка работы программы на время, сравнимое со временем сборки мусора, может привести к критическим ошибкам, использовать в подобной ситуации сборку мусора, очевидно, нельзя.
Наличие некоторого резерва свободной памяти
Чем больше памяти доступно среде исполнения, тем реже запускается сборщик мусора и тем эффективнее его работа. Работа сборщика мусора в системе, где количество доступной сборщику памяти приближается к пиковой потребности программы, может оказаться неэффективной и непроизводительной. Чем меньше избыток памяти, тем чаще происходит запуск сборщика и тем больше времени тратится на его выполнение. Падение производительности программы в таком режиме может оказаться слишком существенным.
Вопреки часто встречающимся утверждениям, наличие сборки мусора вовсе не освобождает программиста от всех проблем управления памятью.
Освобождение других ресурсов, занятых объектом
Помимо динамической памяти, объект может владеть и другими ресурсами — подчас более ценными, чем память. Если объект при создании открывает файл, по завершении использования он должен его закрыть, если подключается к СУБД — должен отключиться. В системах с ручным управлением памятью это делается непосредственно перед удалением объекта из памяти, чаще всего — в деструкторах соответствующих объектов. В системах со сборкой мусора обычно есть возможность выполнить некоторый код непосредственно перед удалением объекта, так называемые финализаторы, но для освобождения ресурсов они не годятся, так как момент удаления заранее неизвестен, и может оказаться, что ресурс освобождается намного позже, чем перестает использоваться объект. В подобных случаях программисту все равно приходится отслеживать использование объекта вручную и вручную выполнять операции по освобождению занятых объектом ресурсов. В C# специально для этой цели существует интерфейс IDisposable, в Java — AutoCloseable.
Утечка памяти
В системах со сборкой мусора тоже могут возникать утечки памяти, правда, имеющие несколько другую природу. Ссылка на неиспользуемый объект может сохраниться в другом объекте, который используется и становится своеобразным «якорем», удерживающим ненужный объект в памяти. Например, созданный объект добавляется в коллекцию, используемую для вспомогательных операций, потом перестает использоваться, но не удаляется из коллекции. Коллекция удерживает ссылку, объект остается достижимым и не подвергается сборке мусора. Результатом становится все та же утечка памяти.
Чтобы устранить подобные проблемы, среда исполнения может поддерживать специальное средство — так называемые слабые ссылки. Слабые ссылки не удерживают объект и превращаются в null, как только объект исчезает — поэтому код должен быть готов к тому, что однажды ссылка укажет в никуда.
Потеря эффективности при операциях с частым выделением и освобождением памяти
Некоторые действия, вполне безобидные для систем с ручным управлением памятью, в системах со сборкой мусора могут порождать несоразмерно большие накладные расходы. Классический пример подобной проблемы приведен ниже.
String out = ""; // Предполагается, что strings содержит большое количество коротких строк, // из которых нужно собрать одну большую строку в переменной out. for( String str : strings ) { out += str; // Данный код будет каждую итерацию создавать // новую строковую переменную и выделять под нее память. }
Данный код на языке Java выглядит так, как будто переменная out, созданная однажды, в цикле каждый раз «дописывается» новой строкой. В действительности же строки в Java неизменяемы, поэтому в данном коде на каждом проходе цикла будет происходить:
При этом каждый раз блок памяти, в котором ранее находилось значение переменной out, будет выходить из употребления и ждать до запуска сборщика мусора. Если объединяется подобным образом 100 строк по 100 символов, то суммарно на данную операцию будет выделено более 500000 байт памяти, то есть в 50 раз больше, чем размер конечной «длинной» строки.
Подобные операции, когда достаточно большие объекты в памяти часто создаются и тут же перестают использоваться, ведут к очень быстрому непродуктивному заполнению всей доступной памяти и частому запуску сборщика мусора, что в определенных условиях может сильно замедлить работу программы или, по крайней мере, потребовать выделения ей для работы неадекватно большого объема памяти. Во избежание подобных проблем программист должен хорошо представлять себе механизм автоматического управления памятью. Также иногда могут использоваться специальные средства для эффективного выполнения опасных операций. Так, для оптимизации приведенного выше примера необходимо воспользоваться специальным классом StringBuilder, позволяющим одним действием выделить память сразу под всю строку, а в цикле только дописывать в конец этой строки очередной фрагмент.
Проблемы взаимодействия с инородным кодом и прямой работы с физической памятью
В практическом программировании на языках со сборкой мусора почти невозможно обойтись без взаимодействия с так называемым инородным кодом: API операционной системы, драйверы устройств, внешние программные модули, написанные на других языках, не управляются сборщиком мусора. Иногда возникает необходимость работы непосредственно с физической памятью компьютера; система управления памятью это также ограничивает, если вообще допускает.
Взаимодействие с инородным кодом обеспечивается одним из двух способов: либо на низкоуровневом языке (обычно на Си) пишется обертка для инородного кода, скрывающая низкоуровневые детали, либо непосредственно в язык добавляется синтаксис, обеспечивающий возможность написания «небезопасного» (unsafe) кода — отдельных фрагментов или модулей, для которых программисту предоставлен более полный контроль за всеми аспектами управления памятью.
И первое, и второе решение имеет свои недостатки. Обертки, как правило, сложны, требуют высокой квалификации для разработки, могут быть плохо переносимы. (Впрочем, их создание может быть автоматизировано. Например, существует мультиязыковой генератор SWIG, который по имеющимся заголовочным файлам Си/C++ автоматически создает обертки для целого ряда языков, поддерживающих сборку мусора.) Они подвержены устареванию: обертка, написанная для одной реализации языка, может стать непригодной для использования в другой, например, при переходе от неперемещающего сборщика мусора к перемещающему.
Специальный синтаксис для небезопасного кода является «легальной дырой» в механизме управления памятью и источником трудно обнаруживаемых ошибок; при этом самим своим наличием он провоцирует программиста на обход языковых ограничений.
Кроме того, любое вмешательство в работу сборщика мусора (а оно неизбежно при взаимодействии с инородным кодом) потенциально снижает эффективность его работы. Например, фиксация в памяти определенного региона, которая необходима, чтобы во время работы с этой памятью инородного кода сборщик мусора не удалил и не переместил его, может ограничить возможность дефрагментации памяти и тем самым затруднить последующее выделение фрагментов нужного размера, даже при наличии достаточного общего объема свободной памяти.
По сравнению с ручным управлением памятью сборка мусора безопаснее, поскольку она предотвращает утечки памяти и возникновение висячих ссылок из-за несвоевременного удаления объектов. Она упрощает и сам процесс программирования.
Считается, что сборка мусора заметно сокращает трудозатраты на управление памятью по сравнению с языками, где она не реализована. Согласно исследованию , программисты на Си тратят 30 % — 40 % общего времени разработки (не считая отладки) только на управление памятью. Впрочем, существуют исследования с противоположными выводами, например, в работе утверждается, что реальная разница в скорости разработки программного обеспечения на C++, где нет автоматической сборки мусора, и на Java, где она реализована, невелика.
Наличие сборщика мусора у неопытного разработчика может создать ложное убеждение, что ему вообще не нужно уделять внимание управлению памятью. Хотя сборщик мусора действительно сокращает проблемы неправильного управления памятью, но не устраняет их полностью, а те, что сохраняются, проявляются не в очевидных ошибках, таких как общая ошибка защиты, а в неоправданном расходовании памяти при работе программы. Типичный пример: если программист упустил из виду, что на объект остался хотя бы один необнуленный указатель в глобальной области видимости, такой объект никогда не будет удален; поиск такой псевдоутечки может быть очень сложным.
Зачастую критически важной является не только гарантия освобождения ресурса, но и гарантия того, что он освободится до вызова какой-то другой процедуры — например, открытые файлы, входы в критические секции. Попытки отдать управление этими ресурсами сборщику мусора (через финализаторы) будут неэффективны или даже некорректны, поэтому приходится управлять ими вручную. В последнее время даже в языках со сборщиком мусора вводят синтаксис, гарантирующий выполнение «кода очистки» (например, специального метода-«деструктора») при выходе переменной, ссылающейся на объект, из зоны видимости.
Во многих случаях системы со сборкой мусора демонстрируют меньшую эффективность, как по скорости, так и по объему используемой памяти (что неизбежно, так как сборщик мусора сам потребляет ресурсы и нуждается в некотором избытке свободной памяти для нормальной работы). Кроме того, в системах со сборкой мусора сложнее реализуются низкоуровневые алгоритмы, требующие прямого доступа к оперативной памяти компьютера, поскольку свободное использование указателей невозможно, и прямой доступ к памяти требует наличия специальных интерфейсов, написанных на низкоуровневых языках. С другой стороны, в современных системах со сборкой мусора используются очень эффективные алгоритмы управления памятью, дающие минимальные накладные расходы. Нельзя также не учитывать тот факт, что сейчас оперативная память относительно дешева и доступна. В таких условиях ситуации, когда критическими для эффективности программы становятся именно затраты на сборку мусора, крайне редки.
Существенное преимущество сборки мусора проявляется тогда, когда динамически созданные объекты живут длительное время, многократно дублируются, а ссылки на них передаются между различными участками программы. В таких условиях достаточно сложно определить место, где объект перестал использоваться и его можно удалять. Поскольку именно такая ситуация складывается при широком использовании динамически изменяемых структур данных (списки, деревья, графы), сборка мусора является необходимой в широко использующих такие структуры функциональных и логических языках, типа Хаскелла, Лиспа или Пролога. Использование сборки мусора в традиционных императивных языках (основанных на структурной парадигме, возможно, дополненной объектными средствами) определяется желаемым соотношением между простотой и скоростью разработки программ и эффективностью ее выполнения.
Поддержка в некоторых императивных языках автоматического вызова деструктора при выходе объекта из области синтаксической видимости (C++ , Ада, Delphi) позволяет разместить код освобождения памяти в деструкторе и быть уверенным, что он будет вызван в любом случае. Это позволяет сконцентрировать опасные места внутри реализации класса, и не требует лишних ресурсов, хотя и предъявляет более высокие требования к квалификации программиста. Одновременно появляется возможность безопасно освобождать в деструкторе и другие занятые объектом ресурсы.
Альтернативой сборке мусора является технология использования «умных ссылок», когда ссылка на динамический объект сама отслеживает число пользователей и автоматически удаляет объект, когда это число становится нулевым. Известной проблемой «умных ссылок» является то, что в условиях, когда программа постоянно создает в памяти много небольших короткоживущих объектов (например, при обработке списочных структур), они проигрывают сборке мусора в производительности.
Еще с 1960-х годов существует управление памятью на основе регионов — технология, в которой память делится на относительно крупные фрагменты, называемые регионами, и уже внутри регионов память выделяется отдельным объектам. При ручном управлении регионы создаются и удаляются самим программистом, при автоматическом — используются различные виды консервативных оценок, позволяющие определить, когда все объекты, выделенные в пределах региона, перестают быть используемыми, после чего система управления памятью удаляет регион целиком. Например, создается регион, в котором выделяется память для всех объектов, создаваемых внутри определенной области видимости, не передаваемых вовне, и этот регион уничтожается одной командой, когда исполнение программы выходит из данной области видимости. Переход в управлении памятью (неважно — ручном или автоматическом) от отдельных объектов к более крупным единицам во многих случаях позволяет упростить учет времени жизни объектов и одновременно снизить накладные расходы. Реализации (разной степени автоматизированности) регионального управления памятью существуют для многих языков программирования, включая ML, Пролог, Си, Cyclone.
Язык программирования Rust предлагает концепцию «владения», основанную на жестком контроле со стороны компилятора соответствия времени жизни и области видимости объектов. Идея состоит в том, что при создании объекта переменная, которой присваивается ссылка на него, становится «владельцем» этого объекта, и область видимости переменной-владельца ограничивает время жизни объекта. При выходе из области видимости владельца объект автоматически удаляется. Путем присваивания ссылки на объект другой переменной он может быть «заимствован», но заимствование всегда временно и должно быть завершено в пределах времени жизни владельца объекта. «Владение» может быть передано другой переменной (например, объект может быть создан внутри функции и возвращен в ее результате), но при этом исходный владелец теряет доступ к объекту. В совокупности правила построены так, чтобы гарантировать невозможность неконтролируемого изменения объекта через посторонние ссылки. Компилятор статически отслеживает время жизни объектов: любая операция, которая хотя бы потенциально может привести к сохранению ссылки на объект после выхода его владельца из области видимости, приводит к ошибке компиляции, что исключает появление «висячих ссылок» и утечек памяти. Такой подход усложняет технику программирования (соответственно, затрудняя обучение языку), но устраняет необходимость как ручного выделения и освобождения памяти, так и использования сборки мусора.
Производительность трассировки сборщиков мусора - как задержка, так и пропускная способность - в значительной степени зависит от реализации, рабочей нагрузки и среды. Простые реализации или использование в средах с очень ограниченным объемом памяти, особенно в встроенных системах, могут привести к очень низкой производительности по сравнению с другими методами, тогда как сложные реализации и использование в средах с достаточным объемом памяти могут привести к отличной производительности.
Что касается пропускной способности, трассировка по своей природе требует некоторых неявных накладных расходов во время выполнения , хотя в некоторых случаях амортизированная стоимость может быть чрезвычайно низкой, а в некоторых случаях даже ниже, чем одна инструкция на выделение или сбор, что превосходит выделение стека. Ручное управление памятью требует накладных расходов из-за явного освобождения памяти, а подсчет ссылок имеет накладные расходы из-за увеличения и уменьшения счетчиков ссылок и проверки того, переполнился ли счетчик или упал до нуля.
Что касается задержки, простые сборщики мусора останавливают выполнение программы для сборки мусора, которая может происходить в произвольное время и длиться сколь угодно долго, что делает их непригодными для вычислений в реальном времени., особенно встраиваемые системы, и плохо подходят для интерактивного использования или любой другой ситуации, когда низкая задержка является приоритетом. Однако инкрементные сборщики мусора могут обеспечить жесткие гарантии в реальном времени, а в системах с частыми простоями и достаточным объемом свободной памяти, таких как персональные компьютеры, сборка мусора может быть запланирована на время простоя и иметь минимальное влияние на интерактивную производительность. Ручное управление памятью (как в C ++) и подсчет ссылок имеют аналогичную проблему с произвольно длинными паузами в случае освобождения большой структуры данных и всех ее дочерних элементов, хотя они происходят только в фиксированное время, независимо от сборки мусора.
Выделение кучи вручную
Вывоз мусора
Прямое сравнение этих двух случаев затруднительно, поскольку их поведение зависит от ситуации. Например, в лучшем случае для системы сбора мусора выделение просто увеличивает указатель, но в лучшем случае для выделения кучи вручную распределитель поддерживает свободные списки определенных размеров, а для выделения требуется только следование указателю. Однако такое разделение по размеру обычно вызывает большую степень внешней фрагментации, которая может отрицательно повлиять на поведение кеша. Выделение памяти на языке со сборкой мусора может быть реализовано с использованием выделения кучи за кулисами (вместо простого увеличения указателя), поэтому перечисленные выше преимущества производительности не обязательно применимы в этом случае. В некоторых ситуациях, особенно встраиваемые системы, можно избежать накладных расходов как на сборку мусора, так и на управление кучей, предварительно выделив пулы памяти и используя настраиваемую упрощенную схему выделения / освобождения.
Накладные расходы, связанные с барьерами записи, более вероятно будут заметны в программе императивного стиля, которая часто записывает указатели в существующие структуры данных, чем в программе функционального стиля, которая конструирует данные только один раз и никогда не изменяет их.
Некоторые достижения в области сборки мусора можно рассматривать как реакцию на проблемы с производительностью. Ранние коллекционеры были коллекционерами, останавливающими мир, но производительность этого подхода отвлекала от интерактивных приложений. Постепенный сбор позволил избежать этого нарушения, но за счет снижения эффективности из-за необходимости создания барьеров. Методы сбора данных поколений используются как с коллекторами остановки, так и с инкрементными сборщиками для повышения производительности; компромисс в том, что некоторый мусор не обнаруживается как таковой дольше обычного.
продолжение следует...
Часть 1 Отслеживание сборки мусора. Сборка мусора в программировании, утечка памяти
Часть 2 Требования к языку и системе - Отслеживание сборки мусора. Сборка
Часть 3 Сборка мусора в реальном времени - Отслеживание сборки мусора. Сборка
Исследование, описанное в статье про сборка мусора, подчеркивает ее значимость в современном мире. Надеюсь, что теперь ты понял что такое сборка мусора, утечка памяти, достижимость объекта, сбор циклических ссылок и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Языки и методы программирования. Теория трансляции
Комментарии
Оставить комментарий
Языки и методы программирования. Теория трансляции
Термины: Языки и методы программирования. Теория трансляции