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


103

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

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

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

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

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

Спасибо.


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

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

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

Ответы:


87

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

Правило # 1

Не надо.

Это действительно самое главное правило. Справедливо сказать, что большинство случаев использования GC.Collect () - плохая идея, и я подробно рассмотрел это в исходной публикации, поэтому я не буду повторять все это здесь. Итак, перейдем к ...

Правило # 2

Рассмотрите возможность вызова GC.Collect (), если только что произошло какое-то одноразовое событие, и это событие, скорее всего, привело к гибели большого количества старых объектов.

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

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

Правило №1 должно преобладать над Правилом №2 без веских доказательств.

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


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


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

58

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


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

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

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

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

24

А как насчет того, чтобы использовать 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()

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


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

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

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

15

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

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

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

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

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

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

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


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

5
Как можно испортить всю машину?
Адам Р. Грей

13

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


12

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


10

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

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


9

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

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


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

7

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


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

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

6

На самом деле, я не думаю, что вызывать 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).

5

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

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

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


5

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

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


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

4

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

В нашей программе мы обрабатывали таблицы 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() .

Пол Смит


4

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

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

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

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


2

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

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


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

2

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


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

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

2

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

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


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

1

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


1

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


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

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

1

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

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

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.