Утечка памяти Ada.Containers.Formal_Indefinite_Vectors

Я использую экземпляр пакета Ada.Containers.Formal_Indefinite_Vectors для хранения двух видов полиморфных объектов.

У меня есть следующий пакет, в котором я создаю контейнер:

with Interfaces.C;
with Root.Classes.Concrete_1;
with Root.Classes.Concrete_2;

package Root.Vectors is

  type vector_t is tagged limited private;
  subtype vectorIndex_t is Interfaces.C.int range 1 .. Interfaces.C.int'Last;

  procedure pAppend (this : in out vector_t;
                     New_Item : Root.Classes.Parent_t'Class);

  procedure pClear (this : in out vector_t);

private
  --TODO: I have to define it correctly, it could be the problem
  function " = " (Left, Right : Root.Classes.Parent_t'Class)
                return Boolean is (True); 

  MaxSize : constant Natural := Natural'Max 
    (Root.Classes.Concrete_1.Concrete_1_t'Size,
     Root.Classes.Concrete_2.Concrete_2_t'Size);

  package polimorphicVector_pck is new
    Ada.Containers.Formal_Indefinite_Vectors
      (Index_Type                   => vectorIndex_t,
       Element_Type                 => Root.Classes.Parent_t'Class,
       " = "                          => " = ",
       Max_Size_In_Storage_Elements => MaxSize,
       Bounded                      => True);

  type vector_t is tagged limited
    record
      v : polimorphicVector_pck.Vector (Capacity => 1000); --TODO: magic number
    end record;

end Root.Vectors;
package body Root.Vectors is

  procedure pAppend (this : in out vector_t;
                     New_Item : Root.Classes.Parent_t'Class) is

  begin
    polimorphicVector_pck.Append (Container => this.v,
                                  New_Item  => New_Item);
  end pAppend;

  procedure pClear (this : in out vector_t) is

  begin
    polimorphicVector_pck.Clear (Container => this.v);
  end pClear;

end Root.Vectors;

Затем я тестирую его со следующим основным:

with Root.Classes.Concrete_1;
with Root.Vectors;

procedure Main is

  aVector : Root.Vectors.Vector_t;

begin

  for idx in Natural range 1 .. 1000 loop

    declare
      --Concrete_1_t is an unconstrained tagged type that requires constructor
      obj : Root.Classes.Concrete_1.Concrete_1_t :=
        Root.Classes.Concrete_1.fConstructor (Argument => idx);
    begin
      aVector.pAppend (New_Item => obj);
    end;

  end loop;

  -- Trying to clear the vector after all appends; this does not seem to work
  aVector.pClear;

end Main;

Затем я использовал gnatmem, чтобы проверить, нет ли у меня утечки памяти, и показал следующее:

Global information
------------------
   Total number of allocations        :779831
   Total number of deallocations      :5080
   Final Water Mark (non freed mem)   : 26.71 Megabytes
   High Water Mark                    : 26.71 Megabytes

Allocation Root # 1
-------------------
 Number of non freed allocations    :764550
 Final Water Mark (non freed mem)   : 17.50 Megabytes
 High Water Mark                    : 17.50 Megabytes
 Backtrace                          :
   ??:0 ??

Allocation Root # 2
-------------------
 Number of non freed allocations    :5100
 Final Water Mark (non freed mem)   : 119.53 Kilobytes
 High Water Mark                    : 119.53 Kilobytes
 Backtrace                          :
   a-cfinve.adb:220 root.vectors.polimorphicVector_pck.copy

Allocation Root # 3
-------------------
 Number of non freed allocations    :3390
 Final Water Mark (non freed mem)   : 7.78 Megabytes
 High Water Mark                    : 7.78 Megabytes
 Backtrace                          :
   a-cfinve.adb:466 root.vectors.polimorphicVector_pck.find_index

Allocation Root # 4
-------------------
 Number of non freed allocations    :1710
 Final Water Mark (non freed mem)   : 1.32 Megabytes
 High Water Mark                    : 1.32 Megabytes
 Backtrace                          :
   a-cfinve.adb:219 root.vectors.polimorphicVector_pck.copy

Allocation Root # 5
-------------------
 Number of non freed allocations    :   1
 Final Water Mark (non freed mem)   : 8 Bytes
 High Water Mark                    : 8 Bytes
 Backtrace                          :
   ??:0 system.stream_attributes.xdr.i_ssi

Почему течет? Это может быть связано с тем, что «=» всегда возвращает True?

Я правильно реализовал функцию равенства, но результат тот же

Albatros23 27.12.2022 13:43

Придирка к вашему коду: ваш Max_Size — это максимальный размер в битах (из атрибута «Размер»), но для создания экземпляра Formal_Indefinite_Vectors требуется максимальный размер в элементах хранения (обычно в байтах). Таким образом, вы выделяете как минимум в восемь раз больше памяти, чем требуется.

Niklas Holsti 27.12.2022 21:17

Интересно, какой выпуск компилятора вы используете? gnatmem.adb был удален из исходников FSF в 2014 году.

Simon Wright 31.12.2022 19:01

Утечки явно есть; без минимального воспроизводимого примера (в частности, Roots.Classes иерархии) трудно сказать больше

Simon Wright 01.01.2023 10:08

@SimonWright Я нигде не использую динамическое размещение; конкретные классы имеют дискретные члены, максимальный размер которых известен.

Albatros23 05.01.2023 09:04

Если бы вы показали нам код в иерархии Root.Classes, мы могли бы помочь вам больше. Кроме того, какой выпуск компилятора вы используете? и на какой платформе?

Simon Wright 05.01.2023 14:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы создаете контейнер как Bounded:

Bounded => True);

Ограниченные контейнеры размещаются в стеке. Это также задокументировано в spec-файле:

       Bounded : Boolean := True;
       --  If True, the containers are bounded; the initial capacity is the maximum
       --  size, and heap allocation will be avoided. If False, the containers can
       --  grow via heap allocation.

Спасибо за ваш ответ! Итак, у меня нет утечек памяти, эти выделения связаны с объявлением переменной «aVector»?

Albatros23 27.12.2022 14:16

@ Альбатрос23, да

egilhh 27.12.2022 14:27

ой, вопрос новичка xD Большое спасибо

Albatros23 27.12.2022 15:13

Да, Bounded => True должен заставить Formal_Indefinite_Vectors использовать только выделение стека, основываясь на комментариях (и я также бегло просмотрел код). Однако, хотя я никогда не использовал gnatmem, если бы мое первое использование gnatmem дало результаты, которые вы показываете, я бы, конечно, заподозрил, что есть утечки памяти. Я предлагаю вам поэкспериментировать с изменением верхней границы цикла for, например, протестировав 1 .. 0, 1 .. 1, 1 .. 2 и 1 .. 10, и посмотреть, как количество распределений и освобождений сообщаемые gnatmem, зависят от количества операций добавления.

Niklas Holsti 27.12.2022 21:17

Я попытался сделать простую демонстрацию для использования с моим WIP-эквивалентом macOS gnatmem, проблем не возникло. Тем не менее, ваши корни распределения 2, 3 и 4 кажутся очень подозрительными - судя по исходному коду GCC 12.2.0, похоже, что компилятор выделяет память для реализации оператора return!

Simon Wright 31.12.2022 19:07

@SimonWright, как это возможно? У меня есть много переключателей в файле gpr, потому что проект взаимодействует с кодом C++, возможно, это вызвано одним из них. В первый раз у меня был переключатель "-gnata", поэтому весь призрачный код из Ada.Containers.Formal_Indefinite_Vectors выполнялся и замедлял каждое добавление.

Albatros23 05.01.2023 09:12

Помимо совета Никласа поэкспериментировать с разными числами, чтобы увидеть влияние, я бы также попробовал использовать какой-нибудь тривиальный тип элемента (например, целое число), чтобы исключить любое влияние с этой стороны. Также я бы попытался увидеть, что valgrind должен сказать.

Álex 09.01.2023 10:09

Другие вопросы по теме