Как исправить ошибку java.lang.OutOfMemoryError при работе с картинками в мобильном приложении 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При активной работе с графическими данными в мобильном приложении 1С — например, при отображении каталогов товаров, прайс-листов или фотоотчетов с большим количеством изображений — система может аварийно завершать работу с ошибкой java.lang.OutOfMemoryError. В этой статье мы разберем причины нехватки памяти Java Heap в операционной системе Android, проанализируем механизмы работы платформы 1С с графикой и рассмотрим практические способы решения этой проблемы.

Причины возникновения ошибки нехватки памяти

Выясним, почему происходит сбой. В мобильных устройствах под управлением Android под каждый процесс выделяется строго ограниченный объем оперативной памяти (Java Heap и Native Heap). Когда мобильная платформа 1С отображает изображение на форме в элементе типа «Поле картинки», происходит следующее:

  1. Распаковка сжатых файлов в растровую карту: Даже если файл картинки в формате JPEG или PNG занимает на диске всего 30 КБ, при отрисовке в оперативной памяти он декодируется в несжатый массив пикселей (Bitmap). Занимаемый объем рассчитывается по формуле: Ширина × Высота × 4 байта. Изображение размером 1920×1080 пикселей займет в оперативке около 8 МБ.
  2. Масштабирование элементов интерфейса: При масштабировании средствами платформы нативный вызов Bitmap.createScaledBitmap создает в памяти сразу два экземпляра изображения — исходный и сжатый под размер контейнера.
  3. Особенности работы Сборщика мусора (Garbage Collector): При закрытии формы или очистке реквизитов 1С удаляет внутренние ссылки, но системный сборщик мусора Android не сразу освобождает нативную память, выделенную под графические буферы UIView. В результате память накапливается при каждом повторном открытии формы.

Порционная загрузка данных и пагинация (Pagination)

Рассмотрим первый метод оптимизации — отказ от одномоментной загрузки всего массива изображений. Вместо передачи сотен фото за один раз организуем пошаговую (порционную) подгрузку данных с сервера.

На стороне веб-сервиса или серверной базы реализуем выдачу данных страницами (например, по 30–50 элементов в одном пакете):


НомерСтраницы = 0;
РазмерСтраницы = 50;

Пока Истина Цикл
    ОтветСервера = ВебСервис.ПолучитьПрайсЛист(Параметры, НомерСтраницы, РазмерСтраницы);
    Если ОтветСервера.Количество() = 0 Тогда
        Прервать;
    КонецЕсли;
    
    // Обработка текущей порции данных
    ЗагрузитьПорциюВФорму(ОтветСервера);
    
    НомерСтраницы = НомерСтраницы + 1;
КонецЦикла;

Для управления выводом на клиенте можно добавить кнопку «Показать еще» или подгружать данные по мере скроллинга, не перегружая оперативный объем памяти устройства.

Явное очищение ссылок и временного хранилища

Разберем, как правильно освобождать ресурсы платформы 1С при закрытии форм или переключении страниц каталога. Для этого необходимо явно обнулять значения реквизитов и вызывать процедуру УдалитьИзВременногоХранилища().

Пример очистки ссылок на временные хранилища при закрытии формы или смене подчиненных страниц:


&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
    // Очищаем реквизиты формы, хранящие ссылки на картинки
    Для Каждого ТекСсылка Из Объект.СсылкиФотоВХранилище Цикл
        // Явно удаляем данные из временного хранилища
        УдалитьИзВременногоХранилища(ТекСсылка.Значение);
        // Сбрасываем значение реквизита формы
        Объект[ТекСсылка.Ключ] = Неопределено;
    КонецЦикла;
КонецПроцедуры

Важный момент: присвоение переменным и реквизитам значения Неопределено помогает платформе развязать циклические ссылки в контексте 1С, что упрощает работу Garbage Collector.

Подготовка миниатюр (Thumbnails) на стороне сервера

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

Чтобы избежать этой проблемы, подготавливайте сжатые миниатюры заранее на сервере:

  1. На сервере при сохранении файла формируйте миниатюру точных пиксельных размеров (например, 150×150 пикселей).
  2. Передавайте на мобильный клиент только миниатюры для списков и каталогов.
  3. Полноразмерное фото загружайте только тогда, когда пользователь явно открывает детальную карточку конкретного объекта.

Использование элемента «Поле HTML документа» вместо «Поля картинки»

Рассмотрим наиболее эффективный альтернативный подход для вывода большого количества изображений в мобильном приложении. Стандартный элемент формы «Поле картинки» создает отдельный нативный виджет UIView для каждого файла, быстро исчерпывая лимит дескрипторов и памяти.

Использование компонента Поле HTML документа позволяет обойти это ограничение:

  1. Сохраняем полученные картинки во временный каталог мобильного устройства.
  2. Формируем динамический HTML-код с галереей товаров, где картинки выводятся тегами <img src="file://...">.
  3. Передаем сформированную HTML-строку в «Поле HTML документа».

Встроенный движок WebView в Android управляет нативной памятью растровых карт значительно агрессивнее. При закрытии формы достаточно очистить HTML-код и вызывать метод УдалитьФайлы() для очистки временного каталога устройства.

Увеличение лимита памяти Heap через AndroidManifest

Если приложение регулярно работает с графикой высокой четкости и логику нельзя полностью вынести в WebView, проанализируем параметр сборки приложения. При сборке дистрибутива в Сборщике мобильных приложений 1С можно разрешить использование увеличенного размера Java Heap.

Для этого в файле AndroidManifest.xml в теге <application> указывается атрибут:

android:largeHeap="true"

Данный флаг запрашивает у операционной системы увеличенный лимит выделяемой памяти RAM (на многих современных смартфонах это поднимает доступный лимит с 64–128 МБ до 256–512 МБ), что значительно снижает риск возникновения java.lang.OutOfMemoryError.

← На главную