Имя: Пароль:
1C
1С v8
Нехватка памяти
0 Air777
 
17.09.11
15:27
По мотивам
v8: Нехватка памяти

Платформа 8.2.13.219

Код:    

....
Для Каждого СтрокаТаблицы Из ТаблицаДокументов Цикл
   Ссылка=СтрокаТаблицы.Ссылка;
   Объект=Ссылка.ПолучитьОбъект();
   Объект=Неопределено;
КонецЦикла;
ТаблицаДокументов=Неопределено;
...

Течет память. Достигая потолка в 1.5 Гб клиент падает.
Как бороться???
1 Darych
 
17.09.11
15:31
гламурный код
2 Jolly Roger
 
17.09.11
15:32
(0) это, скорее, мозги текут...
3 Air777
 
17.09.11
15:37
(2) Вот зачем сразу хамить?

Разумеется это не кусок реального кода, а пример
показывающий место утечки.
4 ОбычныйЧеловек
 
17.09.11
15:43
(0) Уверен, что утечка памяти именно в этом месте происходит?
5 Jolly Roger
 
17.09.11
15:44
(3) ну дык, какой вопрос - такой и ответ. в приведенном коде никакой утечки нет...
6 Air777
 
17.09.11
15:45
(4)На 100% Перепроверено многократно


Объект=Неопределено;
не выгружает объект из памяти

Даже закрытие обработки тоже не высвобождает память
как в ветке из (0)
7 ОбычныйЧеловек
 
17.09.11
15:48
(6) я согласен с (5) о том, что в приведенном коде утечки быть не должно. То что "Объект=Неопределено;
не выгружает объект из памяти" в данном случае ни о чем не говори, откуда вызывается данный код, в транзакции выполняется?
8 ОбычныйЧеловек
 
17.09.11
15:49
хочешь освободить память, просто сверни\разверни 1ску - память освободится.
9 ОбычныйЧеловек
 
17.09.11
15:50
пролемка у тебя явно где то в другом месте - надо код полостью смотреть
10 Air777
 
17.09.11
15:52
Процедура КнопкаВыполнитьНажатие(Кнопка)
   Выборка=Документы.Реализация.Выбрать(Дата("20110801"),);
   
   Пока Выборка.Следующий() Цикл
       Сообщить(Выборка.Ссылка.Номер);
       Объект=Выборка.ПолучитьОбъект();
       Объект=Неопределено;
   КонецЦикла;
   
   Выборка=Неопределено;
КонецПроцедуры


Демонстрирует проблемму.

(9) действительно помагает!!! Как бы этим еще управлять?
11 Air777
 
17.09.11
15:57
(10) Объем используемой памяти проверяю диспетчером задач
При работе кода используемая память непрерывно ростет,
и да (это прям находка) действительно (!!!) когда сернуть/развернуть окно она высвобождается.

Искренне верил что она должна освобождаться сразу же в процессе работы процедуры ну или по ее завершению или хотя бы по закрытию обработки ан НЕТ!
12 Jolly Roger
 
17.09.11
16:00
и как только у людей перепроведение документов работает? в цикле получают тысячи объектов...
13 ОбычныйЧеловек
 
17.09.11
16:00
(11) К сожалению не могу поверить твой код на утечку памяти (дома нету 1Ски), но утечки быть в этом коде не должно (кстати выборку лучше запросом делать).А на счет свертки\разветки приложения  - ты можешь это делать в момент выполнения обработки (в диспетчере на процессе говоришь свернуть и вуаля память очищена :))
14 shuhard
 
17.09.11
16:03
(13)[в диспетчере на процессе говоришь свернуть]
угу,
в час ночи резко ворваться в серверную и отнять у шедулера мышь
15 Air777
 
17.09.11
16:06
(12) возьми код из (10) воткни в новую пустую обработку и убедись воочию. Потом поговорим.
16 Jolly Roger
 
17.09.11
16:22
(15) э нет, спасибо. нафтыкался уже...
17 shuhard
 
17.09.11
16:23
(15)  у меня каждую ночь вот такая обработочка документы перепроводит, не падает, документов много, УПП

Если Не Константы.ИспользоватьФоновоеПерепроведение.Получить() Тогда
       Возврат;
   КонецЕсли;    
       
       ШаблонПодзапроса = "
   |ВЫБРАТЬ  
   |    Ссылка                    КАК Регистратор,
   |    Дата            КАК Дата
   |ИЗ Документ.%ИмяДокумента%
   |ГДЕ
   | Дата >= &ДатаНачала И Дата <= &ДатаОкончания
   |    И Проведен
   |ОБЪЕДИНИТЬ ВСЕ";
   
   ТекстЗапроса = "";
   //Текст запроса складывается объединением из идентичных запросов по документам, которые являются регистраторами для регистра ДокументыТребующиеДопроведения
   РегистрМД = РегистрыСведений.ДокументыТребующиеДопроведения.СоздатьНаборЗаписей().Метаданные();
   Для каждого ДокументМД из Метаданные.Документы цикл
           ТекстЗапроса = ТекстЗапроса + стрЗаменить(ШаблонПодзапроса,"%ИмяДокумента%", ДокументМД.Имя);
   КонецЦикла;
   //Уберем последнее ОБЪЕДИНИТЬ ВСЕ из текста запроса
   ТекстЗапроса = Лев(ТекстЗапроса, СтрДлина(ТекстЗапроса) - 14);
   ТекстЗапроса=ТекстЗапроса+ " Упорядочить ПО Дата,Регистратор";
   Запрос=Новый Запрос;
   Запрос.Текст= ТекстЗапроса;
   // организуем цикл по дате, на каждый день отдельный запрос
   ДатаПерепроведения=Константы.ДатаСтартаПерепроведения.Получить();
   Пока ДатаПерепроведения <=ТекущаяДата() Цикл
       Запрос.УстановитьПараметр("ДатаНачала",НачалоДня(ДатаПерепроведения)) ;
       Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаПерепроведения));
       // собственно запрос
       ТЗ=Запрос.Выполнить().Выгрузить();
       #Если Клиент Тогда
           мКоличествоДокументов = ТЗ.Количество();
           мФормаПрогрессора = Неопределено;
           //Для небольшого количества документов не имеет смысл показывать форму прогрессора
           Если мКоличествоДокументов > 2 Тогда
               мФормаПрогрессора = ПолучитьОбщуюФорму("ХодВыполненияОбработкиДанных");
               мФормаПрогрессора.НаименованиеОбработкиДанных = "Перепроведение";
               мФормаПрогрессора.КомментарийОбработкиДанных = "Перепроведение";
               мФормаПрогрессора.Значение = 0;
               мФормаПрогрессора.МаксимальноеЗначение = мКоличествоДокументов;
               мФормаПрогрессора.КомментарийЗначения = "Перепроведение ...";
               мФормаПрогрессора.Открыть();
               мНомерОбрабатываемогоДокумента = 0;
           КонецЕсли;
       #КонецЕсли    
       // пробежимся по ТЗ
       // получим объект документа
       // проведем
       Для КАждого СтрокаТЗ Из ТЗ Цикл
           // вложенный цикл    
           ТекДокумент = СтрокаТЗ.Регистратор;
           Попытка
               ДокОбъект = ТекДокумент.ПолучитьОбъект();
               //ДокОбъект.ДополнительныеСвойства.Вставить("ЭтапПроведения", "Допроведение");
               ДокОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
               #Если Клиент Тогда
                   ОбработкаПрерыванияПользователя();
                   Если мФормаПрогрессора <> Неопределено Тогда
                       мНомерОбрабатываемогоДокумента            = мНомерОбрабатываемогоДокумента + 1;
                       мФормаПрогрессора.Значение                = мНомерОбрабатываемогоДокумента;
                       мФормаПрогрессора.КомментарийОбработкиДанных = "Перепроведение за " + Строка(Формат(ДатаПерепроведения,"ДЛФ=DD"));
                       мФормаПрогрессора.КомментарийЗначения    = "Перепроводится:" + мНомерОбрабатываемогоДокумента + " документ из " + мКоличествоДокументов;
                   КонецЕсли;
               #КонецЕсли
           Исключение
               Сообщить("Сбой при проведении:"+Строка(ТекДокумент)+"  "+Строка(ОписаниеОшибки()));
           КонецПопытки;
           // вложенный цикл()    
       КонецЦикла;
       ДатаПерепроведения=ДатаПерепроведения+24*60*60;    
   КонецЦикла;
18 Air777
 
17.09.11
16:38
(17) да да за памятью понаблюдай как-нибудь... Судя по всему твои объемы не сопоставимы с моими поэтому ты и не натыкался на эти грабли.


(13) Все плохо. Вот нашел старую ветку с аналогичной ситуацией но для 7.7

Высвобождение памяти 1С 7.7

Пост №14:

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



Проверил у себя на 8.2 - ВСЕ ТАК ЖЕ
память действительно высвобождается однако ВИРТУАЛЬНАЯ память остается НЕИЗМЕННОЙ!!!

Блин что же делать?!
19 shuhard
 
17.09.11
16:46
(18) как ни странна, проблема с утечкой памяти в моем коде решена

у 1С фича, на освобождение памяти влияет то, как получен Объект

тем таких на мисте достаточно
20 ОбычныйЧеловек
 
17.09.11
16:47
(18) утечки памяти в твоем коде быть не должно.....посмотри что в модуле документа написано (скорее всего проблема там)
21 zladenuw
 
17.09.11
16:54
а таблица документов, в ней сколько элементов ? я выгрузку КД с 7.7 загонял в 1,5 гб при выгрузке 200 000 элементов в хмл. когда еще выгружалось.
22 Air777
 
17.09.11
16:58
(19) Напиши объем занимаемой виртуальной памяти процессом 1cv8.exe в диспетчере на вечер и на утро после работы твоей обработки поглядим.

(21) Где ты видишь в (10) обращение к модулю документа????

Сейчас для своего успокоения сделаю пустую тестовую базу и попытаюсь воспроизвести проблему.
23 Air777
 
17.09.11
16:58
(20) Где ты видишь в (10) обращение к модулю документа????
24 Jolly Roger
 
17.09.11
17:08
(23) дык вот же:

Объект=Выборка.ПолучитьОбъект();
25 zladenuw
 
17.09.11
17:19
(24) то да но почему тогда не идет освобождения памяти если  Объект=Ссылка.ПолучитьОбъект();
   Объект=Неопределено;
Или даже при таком присвоение, выделенная память для объекта остается такой же.
26 trambalda
 
17.09.11
17:20
Не очень понятно, почему выборка делается не запросом.
27 Air777
 
17.09.11
17:24
(26) это сути не меняет. Я пробовал обоими способами. Тут приведен пример без запроса для упрощения
28 zladenuw
 
17.09.11
17:26
Слушай может глупо но попробовать так
Процедура КнопкаВыполнитьНажатие(Кнопка)
   Выборка=Документы.Реализация.Выбрать(Дата("20110801"),);
   Пока Выборка.Следующий() Цикл
       Объект=Неопределено;
Сообщить(Выборка.Ссылка.Номер);
       Объект=Выборка.ПолучитьОбъект();        
   КонецЦикла;    
   Выборка=Неопределено;
КонецПроцедуры
29 Air777
 
17.09.11
17:29
Итак отчитываюсь.
Считаю проблема имеет место быть.

Здесь лежит тестовая база http://files.mail.ru/3MVBPS
В ней 8тыс не проведенных документов и обработка из (10)

Вот результаты тестирования:
По объем памяти/виртуальной памяти в МБ

0.Запуск базы 42.5/25
1.Первый запуск обработки "Выполнить" 60.1/40.1
2.Второй запуск 60.9/40.7
3. 61.5/41.3
4. 62.2/42.8
5. 62.8/43.5

ПОЖАЛУЙСТО ПРОВЕРЬТЕ ВОСПРОИЗВОДИМОСТЬ РЕЗУЛЬТАТА
Судя по всему нужно обращаться в саппорт 1с с багрепортом.
30 Fragster
 
гуру
17.09.11
17:29
я поборол итератором в обработке ожидания
31 Air777
 
17.09.11
17:32
(28) результат не изменило
(30) по подробнее пожалуйсто
32 ОбычныйЧеловек
 
17.09.11
18:41
(29) ты не слушаешь...проверь модули документов (утечка именно там) а не твоем вложенном коде.
33 Air777
 
17.09.11
18:58
(32) Как нах код????

ГЛАЗА ОТКРОЙ (29) тестовая база с пустыми НЕ ПРОВЕДЕННЫМИ документами С ПУСТЫМ модулем проведения.

Результат тот же!

О чем ты мне толкуешь?
34 ОбычныйЧеловек
 
17.09.11
19:16
(33) в (29) ни слова не было о том, что доки с пустым модулем объекта... убери "сообщить" и посмотри как будет "расти" память.
35 Air777
 
17.09.11
19:27
(34) безтолку
36 ОбычныйЧеловек
 
17.09.11
19:36
(35) вот не поленился, скачал базу (даже 1Ску поставил) - доков 14тыс. создал (убрал сообщение) - память не растет.
37 Air777
 
17.09.11
19:57
(36) А ведь ты прав!

Наконец то я понял в чем дело и где утечка.

Процедура КнопкаВыполнитьНажатие(Кнопка)
   Выборка=Документы.Реализация.Выбрать(Дата("20110801"),);
   
   Пока Выборка.Следующий() Цикл
       Объект=Выборка.ПолучитьОбъект();
       Сообщить(Объект.Номер);
       Объект=Неопределено;
   КонецЦикла;
   
   Выборка=Неопределено;
КонецПроцедуры


Вот так утечки нет!!!!!!!!!!!!!!!!


Дело как раз в том что я напрямую читал номер дока из ссылки. Очевидно именно в этот момент тянется все содержимое дока в память, а так как указателя на загружаемый объект нет то он и остается висеть в памяти ибо явно не обнуляется. Офигеть
38 Air777
 
18.09.11
02:03
Какая то мистика.


Процедура КнопкаВыполнитьНажатие(Кнопка)
   
   ТекстЗапроса="
   |ВЫБРАТЬ
   |Ссылка
   |Из
   |Документ.Реализация
   |ГДЕ Дата>=&Дата";
   
   Запрос=Новый Запрос;
   Запрос.Текст=ТекстЗапроса;
   Запрос.Параметры.Вставить("Дата",Дата("20110801"));
   
   ТаблицаЗапроса=Запрос.Выполнить().Выгрузить();
   
   Для Каждого Выборка Из ТаблицаЗапроса Цикл
       Объект=Выборка.Ссылка.Получитьобъект();
       Объект=Неопределено;
   КонецЦикла;
   
   ТаблицаЗапроса=Неопределено;
КонецПроцедуры


И снова утечки :(
39 H A D G E H O G s
 
18.09.11
02:19
Добавь
Объект.Записать(РежимЗаписиДокумента.Запись);

И почитай про объектный кэш.

Читай Габца.
Будь мужиком, блеать!
40 H A D G E H O G s
 
18.09.11
02:20
41 H A D G E H O G s
 
18.09.11
02:20
p.s. Можешь покурить 20 минут, память сама уйдет.
42 Air777
 
18.09.11
03:19
Уже час жду 123Мб отожрала и не отдает зараза
43 H A D G E H O G s
 
18.09.11
07:50
(42) Отдаст, когда понадобиться.
(39) помогло?
44 andrewks
 
18.09.11
09:27
имхо, чел борется с ветряными мельницами, то бишь с виндовозным менеджером памяти. не?
45 H A D G E H O G s
 
18.09.11
12:01
(44) Не.
46 H A D G E H O G s
 
18.09.11
12:02
ПолучитьОбъект() кэширует объект в память. И хранит его.
Даже если контекст освобождается.
20 минут.
или пока _Version не изменится. (при записи).

Как и Ссылка.<ИмяРеквизита>
47 Air777
 
18.09.11
13:19
Память высвободилась но где то далеко через час.

Объект.Записать();
а также
Ссылка.<ИмяРевизита>

действительно сути не меняет!

Меня вот это больше всего и поражает - кэш хранится даже
при освобождении контекста. Это как то очень странно.
Выходит нет ни одной команды чтобы его принудительно  очистить.
48 H A D G E H O G s
 
18.09.11
14:57
Пилятъ.
Это элементарно, Ватсон

Не использовать ПолучитьОбъект()!!!
49 H A D G E H O G s
 
18.09.11
14:59
Без метода Записать().

Действительно, без метода Записать() он на 99,9% случаев не нужен. 0.01% идет на случай XML/XDTO-сериализации, но не суть.

Также не юзать

ВЫБОРКА
ССЫЛКА.<Реквизит>

а - запросы!

Запросы - не кэшируются (платформой).
50 H A D G E H O G s
 
18.09.11
15:00
Да, кстати, я не вполне уверен про кэширование
Справочники.СправочникМенеджер.Выборка(,,,,)

Чего не знаю -того не знаю. Ставлю под сомнение ВЫБОРКУ.

В профайлер не пойду.
Лень.