Что плохого в использовании GC.Collect ()?

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

Скажем, я разрабатываю приложение, в котором использование памяти сильно различается в зависимости от того, что делает пользователь. Жизненный цикл приложения можно разделить на два основных этапа: редактирование и обработка в реальном времени. Предположим, что на этапе редактирования созданы миллиарды или даже триллионы объектов; некоторые из них маленькие, а некоторые нет, некоторые могут иметь финализаторы, а некоторые нет, и предположим, что их время жизни варьируется от нескольких миллисекунд до долгих часов. Затем пользователь решает перейти в режим реального времени. На этом этапе предположим, что производительность играет фундаментальную роль, и малейшее изменение в потоке программы может привести к катастрофическим последствиям. Затем создание объектов сводится к минимально возможному за счет использования пулов объектов и тому подобного, но затем GC неожиданно звонит и отбрасывает все это, и кто-то умирает.

Вопрос: не стоит ли в этом случае вызывать GC.Collect () перед переходом ко второму этапу?

В конце концов, эти два этапа никогда не пересекаются друг с другом во времени, и вся оптимизация и статистика, которые мог бы собрать сборщик мусора, были бы здесь бесполезны ...

Примечание. Как отметили некоторые из вас, .NET может быть не лучшей платформой для такого приложения, но это выходит за рамки этого вопроса. Цель состоит в том, чтобы выяснить, может ли вызов GC.Collect () улучшить общее поведение / производительность приложения или нет. Мы все согласны с тем, что обстоятельства, при которых вы бы сделали это, крайне редки, но опять же, GC пытается угадать и делает это в большинстве случаев идеально, но это все еще о предположениях.

Спасибо.

«Малейшее изменение в потоке программы может привести к катастрофическим последствиям ... кто-то может умереть» - уверены ли вы, что C# .NET достаточно детерминирован для ваших целей?

Steve Jessop 23.09.2008 05:35

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

Sergio Acosta 23.09.2008 05:45

LOL на «одну из тех вещей, которые уважаемые программисты никогда бы не использовали, даже те, кто даже не знает, для чего она нужна»! Программисты, которые используют вещи, не зная почему, вряд ли самые респектабельные в моей книге. :)

The Dag 23.01.2013 20:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
104
3
62 838
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

Я думаю, что вы правы насчет сценария, но я не уверен насчет API.

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

Интересно, но в документации говорится, что AddMemoryPressure следует использовать, когда «небольшой управляемый объект выделяет большой объем неуправляемой памяти». (курсив мой)

Robert Paulson 20.10.2008 05:04

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

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

Истинный. Но автоматические тесты, способные выявить условие ошибки «объект не подходит для сборки мусора, но должен быть», были бы полезны. Это может быть достигнуто с помощью комбинации фабричной логики, логики деструктора и GC.Collect. Например. ваш класс Entity имеет свойство IObjectTracker, обычно нулевое, но назначаемое фабрикой сущностей тестовой цели. Фабрика также уведомляет трекер о рождении объекта, а деструктор уведомляет его (если присутствует) о смерти. Если вы знаете, что «деструктор выполнен для всех объектов, которые можно собирать мусором», вы можете проверить состояние трекера для обнаружения утечек.

The Dag 23.01.2013 21:04

Бывают ситуации, когда это полезно, но в целом этого следует избегать. Вы можете сравнить это с GOTO или ездой на мопеде: вы делаете это, когда вам нужно, но не рассказываете об этом своим друзьям.

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

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

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

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

MasterMastic 09.09.2012 09:18

@ Кен Нет, не могут. Но можете ли вы сделать это лучше? Или вы собираетесь писать код, предполагая определенное оборудование, определенную версию ОС и так далее? Соотношение боль / выгода для этого слишком велико.

The Dag 23.01.2013 20:43

@TheDag ИМО, конечно. Когда я освобождаю память и тому подобное, меня не волнует оборудование, потому что это работа ОС, чтобы с этим справиться. Меня также не волнует ОС, потому что у меня есть интерфейс, общий для всех тех, для которых я программирую. (например, мне все равно, Windows, Mac или Linux: когда я выделяю / освобождаю память в C / C++, это new / delete malloc / dealloc). Я всегда мог ошибаться, поэтому не стесняйтесь поправлять меня.

MasterMastic 24.01.2013 05:28

@MasterMastic malloc имеет только очень простой интерфейс, и его реализации могут существенно различаться. Все зависит от того, какую проблему вы пытаетесь решить. Если бы malloc был «достаточно хорош», вам бы не понадобился пул буферов, не так ли? Разработка на C / C++ - это полный примеров, в которых вы пытаетесь повторно угадать ОС / среду выполнения / библиотеки, потому что вы знаете лучше (а иногда и действительно делаете). Многие приложения, критичные к производительности, полностью избегают использования распределителей системы / времени выполнения. Игры, используемые для предварительного выделения всей памяти при запуске (массивы постоянного размера и т. д.).

Luaan 13.02.2017 12:41

Вызов GC.Collect () заставляет CLR выполнять обход стека, чтобы увидеть, действительно ли каждый объект может быть освобожден путем проверки ссылок. Это повлияет на масштабируемость, если количество объектов велико, а также, как известно, слишком часто запускает сборку мусора. Доверяйте среде CLR и позвольте сборщику мусора запускаться при необходимости.

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

Scott Dorman 23.09.2008 07:17

Меня больше беспокоит сбой приложения из-за исключения нехватки памяти, чем низкая производительность, потому что приложение / сборщик мусора выбрасывает вещи, которые больше не нужны. Кто-нибудь знает, почему Microsoft, кажется, генерирует исключение OOM, не выбрасывая ПЕРВЫЙ мусор? (Без этого ОЧЕРЕДНОГО шага - или, по крайней мере, объяснения того, почему этот шаг, кажется, не предпринимается до выброса исключения OOM, я не уверен, что верю в то, что что-то происходит «автоматически» так, как «должно».

Wonderbird 10.06.2015 20:29

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

Конечно, вы должны профилировать это и убедиться в этом сами.

Ответ принят как подходящий

Из блога Рико ...

Rule #1

Don't.

This is really the most important rule. It's fair to say that most usages of GC.Collect() are a bad idea and I went into that in some detail in the orginal posting so I won't repeat all that here. So let's move on to...

Rule #2

Consider calling GC.Collect() if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die.

A classic example of this is if you're writing a client application and you display a very large and complicated form that has a lot of data associated with it. Your user has just interacted with this form potentially creating some large objects... things like XML documents, or a large DataSet or two. When the form closes these objects are dead and so GC.Collect() will reclaim the memory associated with them...

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

Rule #1 should trump Rule #2 without strong evidence.

Измеряйте, измеряйте, измеряйте.

Я бы сказал, что это просто старая штука. Нет ничего плохого или опасного, если вы знаете, что делаете, и, следовательно, знаете, когда и как это делать, а также о побочных эффектах. Такие вещи, как никогда, никогда не использовать xxxx, помещены туда, чтобы защитить мир от паршивых программистов: D

Jorge Córdoba 03.06.2009 01:39

см. также stackoverflow.com/questions/233596/…

Ian Ringrose 24.09.2009 19:45

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

Silent Sojourner 03.01.2018 23:22

Что ж, GC - одна из тех вещей, с которыми у меня есть отношения любви / ненависти. У нас есть сломал это в прошлом через VistaDB, и мы писали об этом в блоге. Они исправили это, но чтобы получить от них исправления в подобных вещах, требуется ДОЛГОЕ время.

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

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

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

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

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

И чтобы мой ответ был как можно более полным, вам также следует протестировать в Mono, если вы также ориентируетесь на эту платформу. Поскольку это совершенно другая реализация, могут возникнуть совершенно другие проблемы, чем в реализации MS.

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

The Dag 23.01.2013 20:53

Как можно испортить всю машину?

Adam R. Grey 19.05.2016 18:11

Сама .NET Framework никогда не предназначалась для работы в среде реального времени. Если вам действительно нужна обработка в реальном времени, вы должны либо использовать встроенный язык реального времени, который не основан на .NET, либо использовать .NET Compact Framework, работающий на устройстве Windows CE.

Он мог использовать .Net Micro Framework, который был разработан для сред реального времени.

TraumaPony 23.09.2008 09:45

@TraumaPony: проверьте диаграмму внизу этой страницы msdn.microsoft.com/en-us/embedded/bb278106.aspx: Очевидно, что Micro Framework не был разработан для сред реального времени. Однако он был разработан для встроенных сред (например, WinCE), но с меньшими требованиями к энергопотреблению.

Scott Dorman 23.09.2008 13:39

Что с этим не так? Тот факт, что вы подвергаете сомнению сборщик мусора и распределитель памяти, которые имеют гораздо большее представление о фактическом использовании памяти вашим приложением во время выполнения, чем вы.

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

Trap 25.09.2008 14:29

Не говоря уже о том, что сборщики мусора лучше осведомлены о каждом приложении Другой и их потребностях в памяти. GC согласовывает память с ОС, поэтому на него влияет доступная физическая память и все другие процессы на машине, как управляемые, так и неуправляемые. Хотя я сомневаюсь, что сборщик мусора действительно знает, «когда самое подходящее время для сбора» на «индивидуальной основе», у него, скорее всего, будет лучшая стратегия в целом, чем ... ЛЮБОЕ отдельное приложение. ;)

The Dag 23.01.2013 21:12

Желание вызвать GC.Collect () обычно пытается скрыть ошибки, которые вы сделали где-то еще!

Было бы лучше, если бы вы нашли место, где забыли выбросить ненужные вещи.

это возможно обобщение

MickyD 30.01.2012 09:35

А как насчет того, чтобы использовать COM-объекты, такие как MS Word или MS Excel, из .NET? Не вызывая GC.Collect после освобождения COM-объектов, мы обнаружили, что экземпляры приложения Word или Excel все еще существуют.

На самом деле код, который мы используем:

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

Так будет ли это неправильным использованием сборщика мусора? Если да, то как заставить умереть объекты Interop? Кроме того, если он не предназначен для такого использования, почему метод GCCollect даже Public?

Это стало бы отличным новым вопросом StackOverflow, а именно: как искоренить экземпляры COM, не вызывая сборщик мусора. Особое внимание уделяется неуправляемым циклическим ссылкам. Это одна из проблем, из-за которой я с осторожностью обновлял надстройку VB6 Outlook до C#. (Мы проделали большую работу по разработке шаблонов кодирования и тестовых примеров на стороне VB, которые гарантировали, что ссылки COM детерминированно уничтожались, когда они больше не нужны).

rkagerer 08.11.2012 03:25

Если это относится к COM-объектам в целом, возможно, это допустимый сценарий. Но сразу же я бы сказал, что проблема заключается в том, что вы используете клиентское приложение, разработанное для интерактивного рабочего стола, в качестве COM-сервера. Из базы знаний MSDN: «Microsoft в настоящее время не рекомендует и не поддерживает автоматизацию приложений Microsoft Office из любых автоматических, неинтерактивных клиентских приложений или компонентов (включая ASP, ASP.NET, DCOM и NT Services), потому что Office может демонстрировать нестабильное поведение и / или взаимоблокировку при запуске Office в этой среде ».

The Dag 23.01.2013 21:08

@TheDag - Microsoft может не рекомендовать, но многим из нас приходилось переносить старый код VB6 с офисным взаимодействием в приложения Windows .Net. Я потратил месяцы работы, пока наконец не избавился от всех невидимых висящих ссылок для большого проекта преобразования VB6 в .Net. Тем не менее, помогло научиться выпускать в обратном порядке назначения и удерживать локальные ссылки для КАЖДОГО отдельного com-объекта, включая коллекции.

Dib 06.10.2014 02:17

В .net время, необходимое для выполнения сборки мусора, гораздо сильнее зависит от количества материала, который не является мусором, чем от количества того, что есть. В самом деле, если объект не переопределяет Finalize (явно или через деструктор C#), является целью WeakReference, находится в куче больших объектов или является особенным каким-либо другим способом, связанным с gc, единственное, что идентифицирует память, в которой он сидит как объект - это наличие корневых ссылок на него. В противном случае работа сборщика мусора аналогична изъятию из здания всего ценного и подрыву здания, постройке нового на месте старого и размещению в нем всех ценных предметов. Усилия, необходимые для взрыва здания, совершенно не зависят от количества мусора внутри него.

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

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

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

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

В обоих случаях результат был прост: нет GC.Collect, не хватает памяти, постоянно; GC.Collect, безупречная работа.

Я пытался решить проблемы с памятью несколько раз, но безрезультатно. Я вынул.

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

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

Создание образов в цикле - даже если вы вызываете dispose, память не восстанавливается. Сбор мусора каждый раз. Я перешел с 1,7 ГБ памяти в моем приложении для обработки фотографий до 24 МБ, и производительность отличная.

Абсолютно время, когда вам нужно вызвать GC.Collect.

Вызов Dispose - это освобождение управляемой памяти не должен. Похоже, вы не знаете, как работает модель памяти в .NET.

Andrew Barber 23.10.2012 00:55

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

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

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

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

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).

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

В нашей программе мы обрабатывали таблицы Excel небольшого размера с помощью OpenXML. Таблицы содержали от 5 до 10 "листов" примерно с 1000 строками по 14 столбцов.

Программа в 32-битной среде (x86) выйдет из строя с ошибкой «нехватка памяти». Мы действительно заставили его работать в среде x64, но нам нужно было лучшее решение.

Мы нашли один.

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

Вызов GC из подпрограммы не работал. Память так и не вернулась ...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

Перемещая вызов GC за пределы подпрограммы, мусор был собран, а память была освобождена.

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

Я надеюсь, что это поможет другим, которые разочарованы сборкой мусора .NET, когда кажется, что она игнорирует вызовы GC.Collect().

Пол Смит

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

Разрешить фоновому процессу заниматься манипуляциями с памятью - значит не заниматься этим самим, правда. Но логически это не означает, что нам лучше не заниматься этим самостоятельно ни при каких обстоятельствах. ГХ оптимизирован для большинства случаев. Но логически это не означает, что он оптимизирован во всех случаях.

Вы когда-нибудь отвечали на открытый вопрос, например, «какой алгоритм сортировки лучший», с однозначным ответом? В таком случае не прикасайтесь к ГХ. Для тех из вас, кто спрашивал об условиях или давал ответы типа «в этом случае», вы можете перейти к изучению GC и того, когда его активировать.

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

Другие вопросы по теме