Имя: Пароль:
1C
1С v8
Загрузка XML большого обьема
,
0 RolandGrey
 
10.02.15
07:50
Имеется необходимость загружать в 1Ску хмл большого объема (от 500 000 строк). Обработка грузит через объект ЧтениеХМЛ. Пробовал писать каждый считанный объект в базу или сразу пачкой (до 1000 за раз) - 1с все равно выжирает всю память и падает.

Что можно предпринять? разбивать файл на куски руками и каждый раз загружать новый кусок в новой сессии не вариант. Пробовал в обработке разбивать файл на куски и закрывать-открывать чтениеХМЛ заново - не помогает.
1 Cube
 
10.02.15
07:54
(0) В качестве бреда: создай пустую базу, подключись к ней по COM из своей боевой. В COM-базе читай разные куски XML с закрытием/открытием COM-соединения после каждого куска :)
2 ShoGUN
 
10.02.15
07:55
(0) Версия платформы 1с какая? Больно странные симптомы, похоже на баг.
3 GenV
 
10.02.15
07:58
(0) Определись из-за чего падает - из-за записи большого объема данных или во время чтения из XML. Тогда можно думать дальше.
4 Рэйв
 
10.02.15
07:59
может поможет
http://infostart.ru/public/304764/
5 RolandGrey
 
10.02.15
09:25
платформа 8.3.5.1383. Смотрел на файловом пока варианте.
Мониторю уровень отжираемой памяти - падает +- при одном объеме.

(2) я пробовал писать сразу всю таблицу, пробовал писать кусками по 1000 объектов, пробовал писать сразу по одному. В любом случае память отжирается и все падает, где-то быстрее где-то медленнее.

(3) как это определить?

(4) как я понял последовательный вызов из основной обработки обработку чтения узла. Попробую, если ничего не поможет
6 Зеленый Кот
 
10.02.15
09:29
это элементарно!
пишешь обработку на vc++ которая читает xml и толкает в 1С по OLE
7 ShoGUN
 
10.02.15
09:31
(5) На 8.3.5.1383 есть проблемы как раз с падением при большом потреблении памяти, лично сталкивался, правда, на серверной. Попробуй обновиться, возможно, извращаться не придётся. По крайней мере, это быстро можно сделать.
8 Зеленый Кот
 
10.02.15
09:33
(7) +1
9 ShoGUN
 
10.02.15
09:49
Во всяком случае, 1000 объектов - это далеко не самый большой объём транзакции, а последовательное чтение потребляет довольно мало памяти. Не вижу объективных причин для способов вроде (1) или (6).
10 RolandGrey
 
10.02.15
09:56
(7) спасибо, попробую обновиться и отпишу потом - помогло или нет.
11 Зеленый пень
 
10.02.15
09:57
(0) Странно. Что за объекты? ЧтениюXML должен быть фиолетов объем файла, причина скорее всего в другом месте.
12 RolandGrey
 
10.02.15
10:55
(11) пока просто справочник номенклатура. Так ЧтениюХМЛ пофиг :) - 1ска отжирает память и система ее убивает
13 Лодырь
 
10.02.15
10:59
(12) Вопрос, а если читать и не создавать объекты в 1с - 1ска падает? То есть выяснить причина в созданных объектах или в чтении.
14 ShoGUN
 
10.02.15
11:04
(13) В объектах, к гадалке не ходи.
15 Лодырь
 
10.02.15
11:11
(14) Ну и у меня такая же мысль. Но тогда проблема немного другая, как создать кучу объектов и не свалится от переполнения. У меня схожая проблема была при выгрузке. Решил разбиением на мелкие порции.
16 Dmitrii
 
гуру
10.02.15
11:11
http://its.1c.ru/db/metod8dev#content:3617:hdoc:_top:утечки%20памяти

Утечки памяти

В технологическом журнале предусмотрена возможность отслеживания утечек памяти при выполнении заданных участков кода конфигурации. Важным частным случаем контролируемого участка кода конфигурации является процесс. Если в конфигурационном файле технологического журнала контроль утечек памяти задан следующим элементом leaks:

<leaks Collect=1>
  <point Call="client"/>
  <point Сall="server"/>
</leaks>

то в технологический журнал будет выведена информация об объектах, которые были созданы, но не были освобождены между началом и окончанием процесса на сервере (<point Сall="server"/>) и на клиенте (<point Call="client"/>).
17 Dmitrii
 
гуру
10.02.15
11:14
http://its.1c.ru/db/v8std#content:2149184374:hdoc:_top:утечка%20памяти
Следует использовать объекты для последовательной записи и последовательного чтения: ЧтениеXML, ЧтениеТекста, ЗаписьXML, ЗаписьТекста, с помощью которых можно прочитать файл порциями и расходовать память экономно.
При использовании механизмов XDTO неправильно зачитывать в память весь XML-файл целиком (ФабрикаXTDO.ПрочитатьXML(ЧтениеXML)). Вместо этого следует зачитывать XML-файл последовательно, с помощью объекта ЧтениеXML, а его отдельные фрагменты (теги) десериализовывать с помощью фабрики XDTO.

4. Другая распространенная причина неэффективное использование памяти - утечки памяти. К утечкам памяти приводит создание циклических ссылок – память выделяется и не освобождается. Например, если есть объекты, внутри которых вложены другие объекты, и где-то в глубине они ссылаются на самый верхний объект. В результате образуется циклическая ссылка.
Упрощенный пример циклической ссылки:

Данные = Новый Структура;
Данные.Вставить("Ключ", Данные);

Следует разрывать (очищать) ссылки, когда объект становится не нужен.  Например, для примера выше:

Данные.Ключ = Неопределено;

Для выявления утечек памяти можно применять технологический журнал, включив в файл настройки параметров технологического журнала logcfg.xml элемент <leaks>.
18 H A D G E H O G s
 
10.02.15
11:27
(0) Обработка - типовая? Если да - то там есть достаточно туповатое кэширование загруженных, без ограничения по "свежести".
19 RolandGrey
 
10.02.15
12:08
(18) нетиповая

подсказанные решения смогу опробовать только вечером
20 Гёдза
 
10.02.15
12:16
В тз грузишь небось, а потом объекты создаешь?
21 Андрюха
 
10.02.15
12:40
(0) Покажь код загрузки xml
22 RolandGrey
 
10.02.15
12:56
(20) изначально было так. Потом ради эксперимента стал писать кусками по 1000 объектов в тз, потом пообъектно писать начал. Ситуация кардинально не менялась.

(21) телега не моя, я ее дополняю:

    Попытка
        
        // Читаем очередной тэг
        Пока Чтение.Прочитать() Цикл
            
            ф = 1;
            // При чтении открывающего тэга определяются атрибуты этого тэга.
            // Также становится известно имя тэга, по которому определяем обрабатываемый объект
            Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
                
                если найти(Чтение.Имя, "Object") > 0 тогда //новый объект
                    
                    ВсегоСтрок = ВсегоСтрок + 1;
                    
                КонецЕсли;
                
                    
                // В режиме отладки выводим проверочные сообщения
                Сообщить_("Начало нового тэга");
                
                ЧтениеИмя                     = Чтение.Имя;
                ЧтениеУровень                 = ЧтениеУровень + 1;          // Тэг открылся, значит начался новый уровень вложенности
                ЧтениеКоличествоАтрибутов     = Чтение.КоличествоАтрибутов( );
                
                Сообщить_( ЧтениеИмя + " [уровень вложенности " + Строка( ЧтениеУровень ) + "], количество атрибутов " + ЧтениеКоличествоАтрибутов );
                
                // В режиме отладки выводим список атрибутов
                Если РежимОтладки И ЧтениеКоличествоАтрибутов > 0 Тогда
                    Пока Чтение.ПрочитатьАтрибут() Цикл
                        Сообщить_( "Атрибут - " + Чтение.Имя );
                    КонецЦикла
                КонецЕсли;
                
                // Тип данных определим для конкретного поля данных или сохраним в нем имя объекта (справочника или документа).
                ЧтениеТипДанных             = "";
                
                // В зависимости от текущего уровня по разному обрабатываем наш тэг
                Если ЧтениеУровень = 3 Тогда
                    
                    // На третьем уровне идет описание объекта (Справочник или Документ)
                    СтрокаОбъектаДанныхXML     = ТЗДанныхXML.Добавить( );
                    
                    СтруктураЗначенийШапки     = Новый Структура;
                    СтруктураЗначенийТЧ     = Новый Структура;
                    
                    // Если имя тэга начинается с CatalogObject, то это справочник
                    Если Найти(ЧтениеИмя,"CatalogObject.") > 0 Тогда
                        ЧтениеТипДанных     = ЧтениеИмя; // Запоминаем его имя
                    // Если имя тэга начинается с DocumentObject, то это документ
                    ИначеЕсли Найти(ЧтениеИмя,"DocumentObject.")>0 Тогда
                        ЧтениеТипДанных     = ЧтениеИмя; // Запоминаем его имя
                    Иначе
                        // Остальное не предусмотрено форматом, поэтому пропускаем
                    КонецЕсли;
                    
                    // Если прочитан правильный тэг (документ или справочник), то добавляем его в строку таблицы сбора данных
                    Если ЧтениеТипДанных <> "" Тогда
                        СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока    = ЧтениеТипДанных;
                    КонецЕсли;
                КонецЕсли;    // ЧтениеУровень = 3
                
                // На четвертом уровне поля шапки документа / справочника
                Если ЧтениеУровень = 4 Тогда // данные шапки только на уровне 4
                    
                    // Ищем указатель на объект, в который необходимо добавить данные
                    // На третьем уровне в СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока было записано имя справочника или документа
                    СтрокаОбъектаДанныхXMLОбъектXMLТипДанных     = НЕОПРЕДЕЛЕНО;
                    // Если это был справочника, то ищем в метаданных описание этого справочника
                    Если Найти(СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока,"CatalogObject.")>0 Тогда
                        // Убираем префикс CatalogObject.
                        СправочникВид     = СтрЗаменить( СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока, "CatalogObject.", "" );
                        Если Метаданные.Справочники.Найти( СправочникВид ) <> НЕОПРЕДЕЛЕНО Тогда
                            СтрокаОбъектаДанныхXMLОбъектXMLТипДанных     = Справочники[СправочникВид];
                        КонецЕсли;
                    // Иначе, это должен быть документ
                    ИначеЕсли Найти(СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока,"DocumentObject.")>0 Тогда
                        ДокументВид     = СтрЗаменить(СтрокаОбъектаДанныхXML.ОбъектXMLТипДанныхСтрока,"DocumentObject.","");
                        Если Метаданные.Документы.Найти( ДокументВид )<>НЕОПРЕДЕЛЕНО Тогда
                            СтрокаОбъектаДанныхXMLОбъектXMLТипДанных = Документы[ ДокументВид ];
                        КонецЕсли;
                    КонецЕсли;
                    
                    // Если у найденного объекта есть табличная часть, то создаем объект для чтения табличной части
                    Если СтрокаОбъектаДанныхXMLОбъектXMLТипДанных <> НЕОПРЕДЕЛЕНО Тогда
                        Если СтрокаОбъектаДанныхXMLОбъектXMLТипДанных.ПустаяСсылка().Метаданные().ТабличныеЧасти.Найти(ЧтениеИмя) <> НЕОПРЕДЕЛЕНО Тогда
                            Сообщить_("Найдена табличная часть");
                            ТЗ             = Новый ТаблицаЗначений;
                            ИмяТЗ         = ЧтениеИмя;
                        КонецЕсли;    
                    КонецЕсли;    
                КонецЕсли;        // ЧтениеУровень = 4
                
                // Пятый уровень не должен ничего содержать. Он говорит о начале новой строки.
                // Поэтому добавляем строку в табличную часть
                Если ЧтениеУровень = 5 Тогда
                    СтрокаТЗ             = ТЗ.Добавить();
                КонецЕсли;
                
                // Начало шестого уровня содержит имя колонки табличной части
                Если ЧтениеУровень = 6 Тогда
                    Если ТЗ.Колонки.Найти( ЧтениеИмя ) = НЕОПРЕДЕЛЕНО Тогда
                        ТЗ.Колонки.Добавить( ЧтениеИмя );    
                    КонецЕсли;
                КонецЕсли;
                
            // Обработка начала тэга звершена
            // Обработка значения тэга
        ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
            
                // Запоминаем текущее значение тэга. В нашем формате, значения могут иметь только поля данных.
                Сообщить_("Значение тэга " + Чтение.Значение );
                ЧтениеЗначение = СокрЛП(Чтение.Значение);
                
        ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
            
                Сообщить_("Тэг завершения");
                // Если завершился третий (для нас верхний) уровоень, то просто запоминаем в табле сбора данных список собранных полей
                Если ЧтениеУровень = 3 Тогда
                    
                    СтрокаОбъектаДанныхXML.ОбъектXMLДанныеШапки = СтруктураЗначенийШапки;
                    СтрокаОбъектаДанныхXML.ОбъектXMLДанныеТЧ     = СтруктураЗначенийТЧ;
                    
                КонецЕсли;
                // Завершение четвертого уровня, говорит о том что прочитано поле данных шапки или строка табличной части
                Если ЧтениеУровень = 4 Тогда
                    
                    // Если была прочитана строка табличной части, то запоминаем ее и создаем новую
                    Если ( ТЗ.Количество( ) > 0 ) И ( ИмяТЗ <> "" ) ТОгда
                        СтруктураЗначенийТЧ.Вставить( ИмяТЗ, ТЗ );
                        ТЗ         = Новый ТаблицаЗначений;
                        ИмяТЗ     = "";
                    Иначе
                        // Было прочитано поле данных, добавлем его в шапку
                        Если ЧтениеЗначение <> 0 Тогда
                            СтруктураЗначенийШапки.Вставить(ЧтениеИмя,ЧтениеЗначение);
                        КонецЕсли;
                    КонецЕсли;
                    
                КонецЕсли;
                
                // На пятом уровне ничего не может быть
                
                // На шестом уровне могут быть только значения табличной части.  
                Если ЧтениеУровень = 6 Тогда
                    СтрокаТЗ[ ЧтениеИмя ] = ЧтениеЗначение;
                КонецЕсли;
                
                
                // Тэг закончился, выходим на уровень вверх
                ЧтениеУровень     = ЧтениеУровень - 1;
                ЧтениеЗначение     = 0;
                
                если найти(Чтение.Имя, "Object") > 0 тогда //новый объект
                    
                    //если всегоСтрок > 1000 тогда
                        
                        записатьТаблицуЗначений(ТЗДанныхXML);
                        ВывестиПрочитанныеДанные(ТЗДанныхXML);    
                        
                        ТЗДанныхXML         = Новый ТаблицаЗначений;
                        ТЗДанныхXML.Колонки.Добавить("ОбъектXML");                                    
                        ТЗДанныхXML.Колонки.Добавить("ОбъектXMLТипДанныхСтрока");
                        ТЗДанныхXML.Колонки.Добавить("ОбъектXMLДанныеШапки");        
                        ТЗДанныхXML.Колонки.Добавить("ОбъектXMLДанныеТЧ");                                  
                        
                        //ТЗДанныхXML.Очистить();
                        //
                        //ТЗДанныхXML.Колонки.Удалить(ТЗДанныхXML.Колонки.Найти("ОбъектXMLТипДанных"));
                        //ТЗДанныхXML.Колонки.Удалить(ТЗДанныхXML.Колонки.Найти("НеЗагружать"));
                        //ТЗДанныхXML.Колонки.Удалить(ТЗДанныхXML.Колонки.Найти("ОбъектНайден"));
                        
                    если всегоСтрок > 1000 тогда

                        всегоСтрок = 0;
                        ВсегоШагов = ВсегоШагов + 1;
                        
                        сообщить("Шаг № " + ВсегоШагов);
                        
                    КонецЕсли;
                    
                КонецЕсли;

            КонецЕсли;
            
        КонецЦикла; // Конец цикла чтения XML файла
        
        //если ВсегоСтрок > 0 тогда
        //    
        //    записатьТаблицуЗначений(ТЗДанныхXML);
        //    ВывестиПрочитанныеДанные(ТЗДанныхXML);    
        //    
        //КонецЕсли;
        
    Исключение
        
        Сообщить( ОписаниеОшибки( ) );
        Возврат Результат;
        
    КонецПопытки;
23 sda553
 
10.02.15
12:59
24 RolandGrey
 
10.02.15
13:03
(23) с помощью DOM приятнее работать, но большие вещи это дело в принципе не переваривает.
25 Fragster
 
гуру
10.02.15
13:03
Чтение.Прочитать();
Пока Чтение.ТипУзла <> ТипУзлаXML.КонецЭлемента Цикл
  Объект = ФабрикаXDTO.ПрочитатьXML(Чтение);
  // Тут объект преобразовываешь/записываешь
КонецЦикла;

а если еще и схема есть, то вообще норм.
26 Fragster
 
гуру
10.02.15
13:04
иногда надо два раза .Прочитать()
27 Fragster
 
гуру
10.02.15
13:05
в зависимости от входного XML.
Хотя объект из 1000000 строк таким образом без промежуточного "проскакивания" прочитывается
28 RolandGrey
 
10.02.15
13:15
(25) схемы нету

несколько способов уже подсказали, буду пробовать )
29 RolandGrey
 
11.02.15
08:57
в-общем причину, кажется, нашел. Но как правильно устранить не совсем понимаю.

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

вопрос - как правильно организовать вывод сообщений?
30 Лодырь
 
11.02.15
09:02
(29) писать их в лог например. а потом показать лог.
Требовать и эффективности, и гибкости от одной и той же программы — все равно, что искать очаровательную и скромную жену... по-видимому, нам следует остановиться на чем-то одном из двух. Фредерик Брукс-младший