При активной работе с графическими данными в мобильном приложении 1С — например, при отображении каталогов товаров, прайс-листов или фотоотчетов с большим количеством изображений — система может аварийно завершать работу с ошибкой java.lang.OutOfMemoryError. В этой статье мы разберем причины нехватки памяти Java Heap в операционной системе Android, проанализируем механизмы работы платформы 1С с графикой и рассмотрим практические способы решения этой проблемы.
Выясним, почему происходит сбой. В мобильных устройствах под управлением Android под каждый процесс выделяется строго ограниченный объем оперативной памяти (Java Heap и Native Heap). Когда мобильная платформа 1С отображает изображение на форме в элементе типа «Поле картинки», происходит следующее:
Ширина × Высота × 4 байта. Изображение размером 1920×1080 пикселей займет в оперативке около 8 МБ.Bitmap.createScaledBitmap создает в памяти сразу два экземпляра изображения — исходный и сжатый под размер контейнера.UIView. В результате память накапливается при каждом повторном открытии формы.Рассмотрим первый метод оптимизации — отказ от одномоментной загрузки всего массива изображений. Вместо передачи сотен фото за один раз организуем пошаговую (порционную) подгрузку данных с сервера.
На стороне веб-сервиса или серверной базы реализуем выдачу данных страницами (например, по 30–50 элементов в одном пакете):
НомерСтраницы = 0;
РазмерСтраницы = 50;
Пока Истина Цикл
ОтветСервера = ВебСервис.ПолучитьПрайсЛист(Параметры, НомерСтраницы, РазмерСтраницы);
Если ОтветСервера.Количество() = 0 Тогда
Прервать;
КонецЕсли;
// Обработка текущей порции данных
ЗагрузитьПорциюВФорму(ОтветСервера);
НомерСтраницы = НомерСтраницы + 1;
КонецЦикла;
Для управления выводом на клиенте можно добавить кнопку «Показать еще» или подгружать данные по мере скроллинга, не перегружая оперативный объем памяти устройства.
Разберем, как правильно освобождать ресурсы платформы 1С при закрытии форм или переключении страниц каталога. Для этого необходимо явно обнулять значения реквизитов и вызывать процедуру УдалитьИзВременногоХранилища().
Пример очистки ссылок на временные хранилища при закрытии формы или смене подчиненных страниц:
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
// Очищаем реквизиты формы, хранящие ссылки на картинки
Для Каждого ТекСсылка Из Объект.СсылкиФотоВХранилище Цикл
// Явно удаляем данные из временного хранилища
УдалитьИзВременногоХранилища(ТекСсылка.Значение);
// Сбрасываем значение реквизита формы
Объект[ТекСсылка.Ключ] = Неопределено;
КонецЦикла;
КонецПроцедуры
Важный момент: присвоение переменным и реквизитам значения Неопределено помогает платформе развязать циклические ссылки в контексте 1С, что упрощает работу Garbage Collector.
Проанализируем еще одну частую ошибку: передачу на мобильное устройство полноразмерных фото в высоком разрешении с расчетом на то, что платформа 1С сама уменьшит их до размера элемента формы. Из-за этого вызовами Bitmap.createScaledBitmap память заполняется мгновенно.
Чтобы избежать этой проблемы, подготавливайте сжатые миниатюры заранее на сервере:
Рассмотрим наиболее эффективный альтернативный подход для вывода большого количества изображений в мобильном приложении. Стандартный элемент формы «Поле картинки» создает отдельный нативный виджет UIView для каждого файла, быстро исчерпывая лимит дескрипторов и памяти.
Использование компонента Поле HTML документа позволяет обойти это ограничение:
<img src="file://...">.Встроенный движок WebView в Android управляет нативной памятью растровых карт значительно агрессивнее. При закрытии формы достаточно очистить HTML-код и вызывать метод УдалитьФайлы() для очистки временного каталога устройства.
Если приложение регулярно работает с графикой высокой четкости и логику нельзя полностью вынести в WebView, проанализируем параметр сборки приложения. При сборке дистрибутива в Сборщике мобильных приложений 1С можно разрешить использование увеличенного размера Java Heap.
Для этого в файле AndroidManifest.xml в теге <application> указывается атрибут:
android:largeHeap="true"
Данный флаг запрашивает у операционной системы увеличенный лимит выделяемой памяти RAM (на многих современных смартфонах это поднимает доступный лимит с 64–128 МБ до 256–512 МБ), что значительно снижает риск возникновения java.lang.OutOfMemoryError.