Оптимизация использования оперативной памяти

#std725

Область применения: управляемое приложение, мобильное приложение, обычное приложение.

Методическая рекомендация (полезный совет)

1. Не следует разрабатывать решения исходя из неограниченного объема оперативной памяти.  Для многопользовательских систем любое неэффективное использование памяти может катастрофически сказаться на работоспособности.

Следует избегать формирования больших структур данных в памяти. Если объём данных, с которыми работает бизнес-логика, сам по себе ничем не ограничен, его нужно ограничивать искусственно, обрабатывая данные порциями и сохраняя результаты в базу или файлы.

2. При потенциально неограниченных выборках данных из ИБ следует получать данные из базы порциями фиксированного размера.
Например, неправильно:

 Запрос = Новый Запрос;
 Запрос.Текст =
  "ВЫБРАТЬ
  | Номенклатура.Ссылка,
  | Номенклатура.Наименование,
  | Номенклатура.ВидНоменклатуры
  |ИЗ
  | Справочник.Номенклатура КАК Номенклатура";

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

поскольку весь результат запроса сразу помещается в память, в таблицу значений.
Также неправильно:

 Запрос = Новый Запрос;
 Запрос.Текст =
  "ВЫБРАТЬ
  | Номенклатура.Ссылка,
  | Номенклатура.Наименование,
  | Номенклатура.ВидНоменклатуры
  |ИЗ
  | Справочник.Номенклатура КАК Номенклатура";

 РезультатЗапроса = Запрос.Выполнить();
 // Обход результата запроса
 ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
 Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
  // Обработка элемента выборки
  // ...
 КонецЦикла;

поскольку и в этом случае при выполнении запроса его результат будет сначала считан в память целиком (*).

* Примечание. Если используется 32-битная версия платформы, и размер результата запроса превосходит размер имеющейся памяти, то данные будут записаны на диск, а затем считаны оттуда в процессе вызовов Выборка.Следующий().

Правильно ограничивать результат запроса искусственно:

ВсеОбработано = Ложь;
Пока Истина Цикл
 Запрос = Новый Запрос;
 Запрос.Текст =
  "ВЫБРАТЬ ПЕРВЫЕ 1000
  | Номенклатура.Ссылка,
  | Номенклатура.Наименование,
  | Номенклатура.ВидНоменклатуры
  |ИЗ
  | Справочник.Номенклатура КАК Номенклатура
  |ГДЕ
  | <условие выборки необработанных записей>";

 РезультатЗапроса = Запрос.Выполнить();
 ВсеОбработано = РезультатЗапроса.Пустой();
 Если ВсеОбработано Тогда
  Прервать;
 КонецЕсли;

 // Обход порции результата запроса
 ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
 Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
  // Обработка элемента выборки
  // ...
 КонецЦикла;

КонецЦикла;

Также правильно:

 Выборка = Справочники.Номенклатура.Выбрать(..., Отбор);
 Пока Выборка.Следующий() Цикл
  // Обработка элемента выборки
  // ...
 КонецЦикла;

поскольку в этом случае платформа 1С:Предприятие выполняет получение данных из базы порциями фиксированного размера.

Кроме того, число элементов выборки автоматически ограничивает платформа 1С:Предприятие в запросах динамических списков.

3. Недопустимо работать с большими XML документами с помощью объектов встроенного языка, предназначенных для обработки файлов целиком: текстовые документы в ТекстовыйДокумент, XML в ДокументDOM и HTML в ДокументHTML, а также создавать в памяти XDTO-пакеты размером с весь XML-файл целиком.

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

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

При использовании механизмов XDTO неправильно зачитывать в память весь XML-файл целиком (ФабрикаXTDO.ПрочитатьXML(ЧтениеXML)). Вместо этого следует зачитывать XML-файл последовательно, с помощью объекта ЧтениеXML, а его отдельные фрагменты (теги) десериализовывать с помощью фабрики XDTO.

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

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

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

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

Для выявления утечек памяти можно применять технологический журнал, включив в файл настройки параметров технологического журнала logcfg.xml элемент <leaks>.

Подробнее см.:

5. Чрезмерное (неоправданное) применение общих модулей с повторным использованием возвращаемых значений  может также приводить к излишнему потреблению памяти