Разделяй и властвуй крупных объектов для производительности GC - PullRequest
5 голосов
/ 25 марта 2010

На моей работе мы обсуждаем различные подходы к очистке большого объема управляемой памяти ~ 50-100 МБ. На столе два подхода (читай: два старших разработчика не могут согласиться), и у нас нет опыта остальная часть команды не уверена, какой подход более желателен, производительность или ремонтопригодность.

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

Подход № 1: Убедитесь, что все ссылки на объекты в BLOB-объекте разорваны, и пусть GC обрабатывает BLOB-объект и все соединения.

Подход № 2: Реализуйте IDisposable для этих объектов, затем вызовите dispose для этих объектов и установите ссылки на Nothing и удалите обработчики.

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

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

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

Редактировать: чтобы добавить акцент, «капля» памяти - это не один большой объект, а множество мелких объектов, выделенных отдельно.

Немного больше информации на случай, если это будет полезно. у нас были «утечки» в том, что объекты не получали GCed. Оба подхода решают проблему утечки, но на данном этапе это спор, который более уместен.

Ответы [ 7 ]

9 голосов
/ 25 марта 2010

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

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

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

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

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

3 голосов
/ 25 марта 2010

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

Если есть какое-то указание на то, как вы решили проблему, это в установке событий на ноль. Они умеют хранить ссылки на объекты, если они реализованы «задом наперед». Другими словами: поддержание отправителя события в живых и разрушение его клиентов. Отмена подписки должна быть сделана явно.

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

2 голосов
/ 25 марта 2010

Интерфейс IDisposable не имеет ничего общего со сборкой мусора.

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

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

Следовательно, создание идентификаторов объектов не повлияет на сборку мусора. Даже использование метода Dispose для очистки всех ссылок практически не повлияет на работу сборщика мусора; просто очистка ссылок на ваш большой двоичный объект позволит всем вашим меньшим объектам сразу же выкорчевать.

1 голос
/ 25 марта 2010

Подход № 2. Внедрение ID можно эти объекты затем называют утилизировать на эти объекты и установить ссылки на Ничего и убери обработчики.

...

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

Я думаю, что это не так; Расходы сборщиков мусора обычно зависят от количества живых объектов и их ссылок, а также от количества мертвых объектов (в зависимости от типа ГХ). Если вам не нужен объект (или объекты) и вырежьте пути ссылок от корневых объектов к нему / ним, количество ссылок между «мусорными» объектами не имеет значения. Так что, я бы сказал, просто убедитесь, что за пределами «блобов» не будет свисающих ссылок, и все будет в порядке.

1 голос
/ 25 марта 2010
1 голос
/ 25 марта 2010

Microsoft подразумевает, что Dispose быстрее, чем Finalize, если вам нужна производительность для объектов, которые содержат неуправляемые ресурсы (дескрипторы файлов, дескрипторы GDI и т. Д.). Я не думаю, что это то, что вы пытаетесь достичь (вы ничего не сказали о неуправляемых ресурсах).

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

0 голосов
/ 18 марта 2011

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

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

  1. Если части большого двоичного объекта являются долгоживущими, маловероятно, что какая-либо его часть, независимо от того, как она была недавно выделена, будет собрана до следующей сборки мусора 2-го уровня. Напротив, если кто-то разбирает все ссылки, удерживающие большой двоичный объект, части, которые были выделены последним, могут иметь право на коллекцию уровня 0 или уровня 1. Если достаточное количество объектов в BLOB-объекте сравнительно новое, усилия, необходимые для уничтожения ссылок, хранящихся в более долгоживущих частях, могут быть меньше, чем работа, которую иначе ГК сделал бы, чтобы сохранить новые объекты до следующей коллекции уровня 2. ,
  2. Если существует косвенная ссылка на часть большого двоичного объекта, и большой двоичный объект остается нетронутым, эта ссылка может сохранить весь большой двоичный объект. В отличие от этого, если капля разлетается на части, блуждающая ссылка может поддерживать только небольшую ее часть. Это может быть хорошо или плохо. Если альтернативой было бы сохранение всего сгустка в живых, лучше сохранить только небольшую часть. С другой стороны, если выбор между поиском проблемы и ее устранением (устранением ложной ссылки), а не поиском проблемы, первый может быть лучше.

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

...