Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Утечка памяти в методе "Подготовить" объекта "ODBCRecordset" (число прочтений - 1868 )
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
25. Января 2017 :: 14:38
Печать  
Может этот баг уже был описан где-то, или даже исправлен, но я попробовал на паре версий 1С++. Вот такой простой код (для SQL версии) за несколько секунд выедает 1Гб памяти:
Код
Выбрать все
Запрос=СоздатьОбъект("ODBCRecordset");
Для Поз=1 По 5000*20 Цикл
	Запрос.Подготовить("ТЕКСТ ЗАПРОСА");
КонецЦикла; 

Причём запрос не обязательно должен быть реальным, т.е. приведённый код подойдёт дословно. Такой же эффект произведёт вызов в этом цикле метода "Выполнить" с текстом запроса (видимо он вызывает "Подготовить").
"Подготовить" вне цикла с вызовом "Выполнить" в цикле без параметров работает нормально (хотя сам "Подготовить" при этом сколько-то байт памяти съедает, конечно).
Память после уничтожения переменных не освобождается. При закрытии 1С вываливается ошибка.

Аналогичный код с драйвером "MySQL ODBC 3.51 Driver" работает несколько иначе. В процессе выполнения цикла память растёт примерно до 400Мб (причём при большом количестве итераций наступает насыщение и дальше не растёт), после выполнения и уничтожения переменной "Запрос" память возвращается к некоторому фиксированному размеру. 1С завершается без ошибки.

Версии
3.2.3.20
3.2.4.3
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
Ответ #1 - 26. Января 2017 :: 06:52
Печать  
Для Подготовить не критично - Подготовить в цикле не имеет смысла.
Для Выполнить с реальным запросом не воспроизводится. С запросом вида "ТЕКСТ ЗАПРОСА" причина скорее всего другая - есть баг в работе с исключениями в движке 1С (не 1С++).
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
Ответ #2 - 05. Февраля 2017 :: 16:40
Печать  
1. Для "Подготовить" - не критично, когда он запускается у клиента 100 раз в день и он закрывает 1С и уходит домой. Когда 1С работает на сервере круглосуточно и начинает зависать со странным диалоговым окном посреди экрана (стандартный эффект нехватки памяти) - уже другое дело. А вообще, утечки памяти "не критичными" не бывают.
2. Баг в работе с исключениями - мимо. "Выполнить" не выбрасывает исключения, а возвращает 0 в случае неуспеха. Как раз наоборот, при работе с исключениями (то есть через ВыполнитьИнструкцию, ВыполнитьСкалярный) всё работает прекрасно и при возникновении исключений, и без них, утечек памяти нет.
3. "Выполнить" с реальным запросом замечательно воспроизводит проблему:
Код
Выбрать все
	Запрос=СоздатьОбъект("ODBCRecordset");
	Для Поз=1 По 5000*20 Цикл
		Если Запрос.Выполнить("DELETE FROM SC32762 WHERE ISMARK=1")=0 Тогда
			Сообщить("Ошибка");
			Прервать;
		КонецЕсли;
	КонецЦикла;
 

Выедает тот же гигабайт памяти. Как раз на подобном запросе был и пойман.
Здесь ещё есть нюанс. Потестил на разных виндах: на 2008R2 код отрабатывает и выедает гиг памяти. На 2003 останавливается на 800 метрах и выходит из цикла с ошибкой (видимо память уже не может выделить к этому моменту).
Но суть остаётся та же.
Проблема именно в методе "Подготовить" и (видимо) по наследству достаётся от него методу "Выполнить" в варианте с текстом запроса, который является очень даже употребительным в циклах.
  
Наверх
 
IP записан
 
Djelf
God Member
*****
Отсутствует


Ubuntu + wine@etersoft
+ 1C 7.7

Сообщений: 631
Местоположение: Питер
Зарегистрирован: 02. Ноября 2007
Пол: Мужской
Re: Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
Ответ #3 - 05. Февраля 2017 :: 18:56
Печать  
Судя по коду похоже на правду...
Используй Закрыть() после запроса, там память, насколько вижу, должна  очищается.
Если запрос в цикле, видимо его можно Подготовить вне цикла и Закрыть после цикла.

P.S. Не уверен что кто то это починит в 1с++, мой бубен ее собрать так и не помог...
  
Наверх
www  
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
Ответ #4 - 06. Февраля 2017 :: 07:14
Печать  
Да, действительно. Применение "Закрыть" после выполнения запроса работает. В том числе и в варианте без "Подготовить", т.е. после "Выполнить" с текстом запроса.
Таким образом, вариант применения типа "Подготовить">>"Выполнить()" в цикле>>"Закрыть"  ещё можно применить на практике (и то, если добавить обработку исключений между "Подготовить" и "Закрыть", что уже неудобно). А код типа
Код
Выбрать все
Если Запрос.Выполнить("ТЕКСТ ЗАПРОСА")=1 Тогда
  ...
ИначеЕсли Запрос.Выполнить("ТЕКСТ ЗАПРОСА")=1 Тогда
  ...
Иначе
  ... 

и ему подобный превратится в трудно читаемую каку.

В общем, баг, видимо, локализован.
Кто-то забыл вызвать метод "Закрыть" в методе "Подготовить" при уже подготовленном запросе, а также в деструкторе объекта.
А ещё такую чистку стоит предусмотреть и в других методах, как ВыполнитьИнструкцию, ВыполнитьСкалярный и др. Для общности. Бывает даже, что один объект "ODBCRecordset" используется глобально во всей программе для самых разных задач на протяжении недель.
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Утечка памяти в методе "Подготовить" объекта "ODBCRecordset"
Ответ #5 - 07. Февраля 2017 :: 06:40
Печать  
dfuy писал(а) 06. Февраля 2017 :: 07:14:
Кто-то забыл вызвать метод "Закрыть" в методе "Подготовить" при уже подготовленном запросе, а также в деструкторе объекта.

Ты, похоже, не понимаешь, для чего нужен метод Подготовить и почему он отъедает память на клиенте.  Язык
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать