Ответ 1
Часть того, что происходит в GC, состоит в том, что объекты в памяти являются поколенными, так что ранние поколения собираются чаще, чем другие. Это помогает экономить производительность, не пытаясь постоянно собирать долгоживущие объекты.
Имея это в виду, две вещи могут произойти, когда вы вызываете GC.Collect()
самостоятельно. Во-первых, вы тратите больше времени на сбор коллекций. Это связано с тем, что в дополнение к вашему руководству GC.Collect() все равно будут выполняться обычные фоновые коллекции. Во-вторых, вы будете больше держаться за память, потому что вы заставили некоторые вещи покорить более высокие порядки, которые не должны были туда идти. Другими словами, использование GC.Collect() - это почти всегда плохая идея.
Есть несколько случаев, когда сборщик мусора не всегда работает хорошо. Одна из них - куча большого объекта. Это специальное поколение для объектов размером более определенного размера (80 000 байт, IIRC, но это может быть старым сейчас). Это поколение почти никогда не собирается и почти никогда не уплотняется. Это означает, что со временем вы можете получить много значительных дыр в памяти, которые не будут выпущены. Физическая память фактически не используется и доступна для других процессов, но она по-прежнему потребляет адресное пространство внутри вашего процесса, из которого вы по умолчанию ограничены 2 ГБ.
Это очень распространенный источник исключений OutOfMemory — вы на самом деле не используете столько памяти, но у вас есть все это адресное пространство, занятое дырками в большой кучке объектов. На сегодняшний день наиболее распространенным способом это является многократное добавление к большим строкам или документам. Вероятно, это не так, потому что в этом случае количество вызовов в GC.Collect() не будет связано с LOH, но в вашем случае это, похоже, поможет. Однако это источник для подавляющего большинства исключений OutOfMemory, которые я видел.
Другое место, где сборщик мусора не всегда хорошо работает, - это когда определенные вещи заставляют объекты оставаться корнями. Одним из примеров является то, что обработчики событий могут предотвратить сбор объекта. В этом случае убедитесь, что для каждой операции +=
для подписки на событие есть соответствующая операция -=
, чтобы отменить подписку. Но опять же, GC.Collect() вряд ли поможет здесь - объект все еще коренится где-то, и поэтому его невозможно собрать.
Надеюсь, это даст вам возможность провести расследование, чтобы решить вашу основную проблему, из-за которой в первую очередь необходимо использовать GC.Collect(). Но если нет, то, конечно, лучше иметь рабочую программу, чем неудачную программу. В любом месте, где я использую GC.Collect(), я бы удостоверился, что код хорошо документирован по причине, в которой он вам нужен (вы получаете исключения без), а также точные шаги и данные, необходимые для надежного воспроизведения, чтобы будущие программисты, которые могут захотеть чтобы удалить это, вы можете точно знать, когда это безопасно.