Есть статичный метод private static bool GetXml(string date) { try { //Подключаемся к сервису KBODataProviderClient client = new KBODataProviderClient() //Получаем данные string[] result = client.getKBOContracts("2018-12-25", null) //Если данных нет if (result == null || result.Length <= 0) { log.InfoFormat("[{0}]|Pbo return 0 rows", runGuid) return false }<br> if (File.Exists(filePath)) File.Delete(filePath) //Сохраняем XML using (StreamWriter sw = new StreamWriter(filePath, true, Encoding.UTF8)) { //пишем первую запись с заголовков sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>") sw.WriteLine("") for (int i = 0 i < result.Length i++) { //удаляем заголовок string temp = result[i].Replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>", "") sw.WriteLine(temp) } sw.WriteLine("") } log.InfoFormat("[{0}]|Create XML success", runGuid) return true } catch (Exception ex) { log.ErrorFormat("[{0}]|GetXml error {1}", runGuid, ex + Environment.NewLine + ex.StackTrace) return false } } При вызове метода он подключается к WCF сервису, оттуда приходит массив строк (возвращает string[]), который я потом пишу в файлик. Проблема в том, что при получении данных разумеется съедается память, и после завершения метода память не очищается. Собственно, я знаю то, что переменная string[] result является временной переменной и после завершения метода она должна собраться сборщиком мусора, но этого не происходит (данные занимают около 400мб в памяти) Первым, что пришло в голову это проблема из-за статичного метода. Тогда я решил потереть ссылку result = null GC.Collect() и вызвать сборщик самому. Но и тут эффекта 0. В чем проблема? upd: Использование метода идет так: if (GetXml(date)) { //парсинг } сам метод дополнил так: private static bool GetXml(string date) { try { //Подключаемся к сервису KBODataProviderClient client = new KBODataProviderClient() //Получаем данные string[] result = client.getKBOContracts("2018-12-25", null) //Если данных нет if (result == null || result.Length <= 0) { log.InfoFormat("[{0}]|Pbo return 0 rows", runGuid) return false }<br> if (File.Exists(filePath)) File.Delete(filePath) //Сохраняем XML using (StreamWriter sw = new StreamWriter(filePath, true, Encoding.UTF8)) { //пишем первую запись с заголовков sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>") sw.WriteLine("") for (int i = 0 i < result.Length i++) { //удаляем заголовок string temp = result[i].Replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>", "") sw.WriteLine(temp) } sw.WriteLine("") } log.InfoFormat("[{0}]|Create XML success", runGuid) client.Close() client = null result = null GC.Collect() return true } catch (Exception ex) { log.ErrorFormat("[{0}]|GetXml error {1}", runGuid, ex + Environment.NewLine + ex.StackTrace) return false } } Клиент сервиса я закрываю и на всякий даже null присваиваю. Далее присваиваю null строке и вызываю сборщик. В итоге при получении данных память увеличивается до 320мб(+- офк) и после завершения падает до +-211 и продолжает работать. Метод парсинга не занимает столько памяти, т.к без получения данных при парсинге память остается на уровне +-60мб. попробовал Array.Clear, так-же 0 эффекта (скрин выше)
Ответ Проблема решена. Я решил проверить все дело на левых проектах потихоньку перенося код и оказалось чудом, когда на новом проекте память очищалась нормально(требовалось лишь вызвать GC.Collect()) Первым делом я решил проверить версии .net, на проекте где все работало был 4.7.1, но изменение версии не помогло. Тогда я начал в буквальном смысле добавлять по строчке и сверять код. Причина оказалось в app.config, а именно в секции которую генерирует VS при добавлении ссылки на сервис (там указываются таймауты и прочее). Конкретно проблема была в том, что таймауты (CloseTimeout, OpenTimeout, ReceiveTimeout, SendTimeout) указывались в привязке (секция basicHttpBinding). Если я указывал эти таймауты в этой секции - память не очищалась (ни в основном, ни в каких других проектах), т.е если делал так:
но если я указывал таймауты через код: client.Endpoint.Binding.CloseTimeout = new TimeSpan(0, 30, 0) client.Endpoint.Binding.OpenTimeout = new TimeSpan(0, 30, 0) client.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 30, 0) client.Endpoint.Binding.SendTimeout = new TimeSpan(0, 30, 0) то сборщик мусора успешно собирал мусор. Чтобы сделать настройку времени из конфига я воспользовался ConfigurationManager
тогда в коде я делаю так: //Получаем время, переводим его в TimeSpan (если указать их в конфиге, то память не будет очищена) TimeSpan time = new TimeSpan(TimeSpan.TicksPerMinute * int.Parse(ConfigurationManager.AppSettings.Get("timeout"))) client.Endpoint.Binding.CloseTimeout = time client.Endpoint.Binding.OpenTimeout = time client.Endpoint.Binding.ReceiveTimeout = time client.Endpoint.Binding.SendTimeout = time и сборщик мусора так-же успешно очищает память