Упакованные компоненты

Начиная с версии Ehp2 7.0 (ABAP Kernel 7.20) в ABAP появилась возможность использования так называемых упакованных компонентов. Объявить структуру с использованием упакованных компонентов мы можем как локально, с помощью ключевого слова BOXED, так и в словаре, выбрав тип типизации:

Boxed in dictionary

В роли упакованных компонентов могут выступать как простые структуры, так и глубокие структуры (содержащие набор компонентов или другие вложенные структуры), а так же структурные атрибуты классов и интерфейсов. При копировании структур с помощью оператора INCLUDE TYPE|STRUCTURE атрибут BOXED копируется.

Упакованные компоненты позволяют сократить объем выделенной памяти в программе. Достигается это за счёт того что под упакованные компоненты память выделяется только при их реальном использовании (см. ниже). Для обычных же компонентов объявленных через оператор TYPE (не TYPE REF TO), память выделяется автоматически при их инициализации.

Согласно документации, выделение памяти под упакованные компоненты происходит в следующих случаях:

  • Во время записи
  • Во время присвоения ссылочному полю (Field Symbols)
  • Когда компонент передается в любую из подпрограмм (процедуры и т.п.)
  • Когда мы получаем доступ через ссылочную переменною (GET REFERENCE OF)

Операторы CLEAR и FREE не возвращают упакованные компоненты в первоначальное состояние (не сбрасывают выделенную память), а только приводят их компоненты в исходное (initial) состояние.

Пример выделения памяти для структур с разными типами и ссылочной переменной:

В результате система выделит память следующим образом:

Выделение памяти

 

Для упакованного компонента система выделяет 8 байт для хранения ссылки на оригинальную структуру.

В качестве еще одного примера рассмотрим небольшую программу для получения данных о поставщиках и их телефонных номерах:

В тестовых данных моей системы существуют такие поставщики, у которых нет информации о телефонных номерах, соответственно выделение памяти под эти данные не имеет смысла. После заполнения внутренних таблиц мы имеем следующий результат по выделению памяти:

Выделенная память

 

Как видно из рисунка, после выполнения выборки, под вторую таблицу выделено гораздо меньше памяти, за счёт использования упакованных компонентов. Кроме того что использование упакованных компонентов может снизить объем выделенной памяти (в тяжелых случаях избавить от дампов при выделении памяти 🙂 ), их использование так же может ускорить время выполнения программы, за счёт копирования только внутренней ссылки, без копирования дополнительных данных, при операциях над структурными переменными.

Пример того как упакованные компоненты могут быть использованы в классах:

  • Диман

    я не абапер, только учусь… но походу это неправильно работает и память меньше, потому что таблица с пустыми записями…

  • Диман

    Точнее не с пустыми, а в поле lifnr пишется telf*. Как это использовать на практике я не понял. А если lt_tab_b будет заполнена такими же значениями как lt_tab, то памяти она использует больше.

    • Спасибо, пример действительно кривой, ниже более подходящий.

      Зайдя в инструмент анализа памяти можно увидеть как относительно не пустых записей будут созданы ссылочные переменные.

      TABLES: lfa1.

      TYPES:
      » Структура с телефонными данными поставщиков
      BEGIN OF ty_data,
      telf1 TYPE lfa1-telf1,
      telf2 TYPE lfa1-telf2,
      END OF ty_data,

      » Структура без упакованного компонента
      BEGIN OF ty_customer,
      lifnr TYPE lifnr,
      telef TYPE ty_data,
      END OF ty_customer,

      » Структура с упакованным компонентом
      BEGIN OF ty_customer_boxed,
      lifnr TYPE lifnr,
      telef TYPE ty_data BOXED,
      END OF ty_customer_boxed.

      DATA:
      lt_tab TYPE TABLE OF ty_customer,
      lt_tab_b TYPE TABLE OF ty_customer_boxed.

      SELECT lifnr telf1 telf2 FROM lfa1 INTO CORRESPONDING FIELDS OF lfa1.
      APPEND INITIAL LINE TO lt_tab ASSIGNING FIELD-SYMBOL().
      -lifnr = lfa1-lifnr.
      -telef-telf1 = lfa1-telf1.
      -telef-telf2 = lfa1-telf2.

      APPEND INITIAL LINE TO lt_tab_b ASSIGNING FIELD-SYMBOL().
      -lifnr = lfa1-lifnr.

      IF lfa1-telf1 IS NOT INITIAL.
      -telef-telf1 = lfa1-telf1.
      ENDIF.

      IF lfa1-telf2 IS NOT INITIAL.
      -telef-telf2 = lfa1-telf2.
      ENDIF.
      ENDSELECT.

      • Диман

        Михаил, спасибо. Пример рабочий, объем используемой памяти сокращается!