Неудобные вызовы GC.collect() в сторонней библиотеке

Во время профилирования моего приложения (С#,.NET 4) я заметил, что сторонняя библиотека, я использую явно вызовы GC.Collect(). Это очень раздражает, потому что это иногда оказывает существенное влияние на производительность моего приложения, так как некоторые вызовы этой библиотеки заканчиваются огромными циклами: время, затраченное на GC.Collect, составляет более 80% от общего времени выполнения.

Конечно, я сообщил об этом поведении для поддерживающих библиотек (lib не является открытым исходным кодом), но пока они работают над новой версией, я бы хотел оптимизировать свое приложение. Что я могу сделать?

Я попытался настроить GC, установив GCSettings.LatencyMode в GCLatencyMode.LowLatency(конечно, только во время выполнения вызовов библиотеки), но безрезультатно. Я бы предпочел избежать разветвления моего процесса.

Любые идеи?

Ответ 1

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

Исправить это самостоятельно довольно легко, RedGates Reflector вместе с Reflexil AddIn и исправьте библиотеку. Вы также можете получить DotNet IL Editor, который в основном делает то же самое, но FLOSS.

Проблема с подходом "patch it yourself" заключается в том, что у него есть недостатки:

  • Будущие версии библиотек также должны быть исправлены. Поэтому вам лучше вести учет того, что вы сделали.
  • Вы не понимаете внутренности библиотеки, если есть 10 вызовов GC.Collect(), и только один из них является законным (я сомневаюсь, но могу быть), вы разрушите библиотеку, удалив все из них.
  • Скорее всего, вы нарушите лицензию библиотеки, которая может отправить вас в адский ад. Но это зависит от того, как вы используете библиотеку и какое программное обеспечение и как распространяется этот окончательный пакет.

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

Ответ 2

Прежде чем пытаться взломать вещи, чтобы код не выполнял GC, может быть полезно спросить, почему это происходит. В то время как хорошо написанный код должен просто позволить GC быть вызванным, когда .Net считает необходимым, он, безусловно, может писать код, который требует, чтобы GC выполнялся в определенное время, чтобы обеспечить правильность. Я могу представить три причины, по которым код может вызывать GC:

  • Запросы GC были добавлены для целей профилирования памяти и непреднамеренно/ненадлежащим образом оставлены.
  • Разработчик подумал, что это хорошая идея, хотя она не дает никакой реальной выгоды.
  • Некоторый тип управляемого ресурса был неправильно оставлен; принуждение GC может позволить очистку такого заброшенного ресурса достаточно своевременно, чтобы обеспечить правильное (хотя и медленное) выполнение программы.

Если принудительный GC существует из-за сценария 3, его удаление может привести к возникновению плохих вещей.