IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

3 страниц V  1 2 3 >  
 Ответить  Открыть новую тему 
> Отлов утечек памяти - GNAT, (разделено)
сообщение
Сообщение #1


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Новые вопросы - какая функция определяет наличие или отсутствие утечек памяти?
Я скачал ВинАДУ, поставил, как подключить пакет, содержащий заголовки виндовых библиотек? with ADA.Windows не рабтает, нет такого пакета.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Цитата
какая функция определяет наличие или отсутствие утечек памяти?
Целый пакет есть для этого:
with GNAT.Debug_Pools; use GNAT.Debug_Pools;

-- ... Остальные используемые пакеты

procedure Main is

D_Pool : Gnat.Debug_Pools.Debug_Pool; -- Добавляем

-- Тут идут твои функции/процедуры

begin
GNAT.Debug_Pools.Configure (D_Pool, Raise_Exceptions => False);

-- Работаешь со своими функциями/процедурами

GNAT.Debug_Pools.Print_Info_Stdout (D_Pool, Display_Leaks => True);
end Main;
После окончания работы программы получаешь полный список: сколько выделил памяти, сколько освободил, где не освободил...


Цитата
Я скачал ВинАДУ, поставил, как подключить пакет, содержащий заголовки виндовых библиотек? with ADA.Windows не рабтает, нет такого пакета.
Правильно. Его и не было.

with Win32. { тут может быть много дочерних пакетов }


Но сначала открой GPR-файл, и самой первой строкой добавь

with "win32ada";
-- Дальше - то, что и было, описание project ... is
, после чего перезагрузи проект. А еще лучше - сделать это без загруженной IDE. Я всегда так делаю - создаю новый проект, выхожу из IDE, правлю GPR, и загружаю среду заново (ну, или вообще набираю GPR вручную. Там всего - то 10 строк нужно)... Если устанавливал win32ada-gplXXXX.exe и ошибок при установке не было - то все должно завестись.

P.S. Я тут задумал написать про нововведения в A2012, нужно?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> Целый пакет есть для этого:

Всё по нулям выводит, якобы я ничего не выделял и не освобождал.
Total allocated bytes :  0
Total logically deallocated bytes : 0
Total physically deallocated bytes : 0
Current Water Mark: 0
High Water Mark: 0

List of not deallocated blocks:

Хотя сделал ровно так - добавил пакет, описание переменной, инициализацию в начале, вывод в конце.

> with "win32ada";
А это что за конструкция - название в кавычках? Типа заставить среду навсегда подключить набор пакетов?

> P.S. Я тут задумал написать про нововведения в A2012, нужно?
Ну вообще интересно, да.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Цитата
Типа заставить среду навсегда подключить набор пакетов?
Не навсегда, а для данного проекта.

Цитата
Всё по нулям выводит, якобы я ничего не выделял и не освобождал.
Странно... Попробовал "забыть" освободить выделенную память, меня тут же ткнули носом:
Прикрепленное изображение

А. Ну да, я забыл написать про use D_Pool... На скрине видно, как оно используется...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Всё равно непонятно. Как его подключить к указателю, зашитому внутрь объекта из другого пакета? Пока только приходит в голову объявить его в отельном модуле, который подключить ко всем модулям проекта.

А если мне потом понадобится его отрубить, то надо написать как-то D_Pool: Standart_Pool ?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Цитата
А если мне потом понадобится его отрубить
, то не надо его подключать. Это только средство отладки. Закончил отладку (убедился, что утечек нет) - отключай GNAT.Debug_Pools и все use D_Pool.

Цитата
Как его подключить к указателю, зашитому внутрь объекта из другого пакета? Пока только приходит в голову объявить его в отельном модуле, который подключить ко всем модулям проекта.
Правильно. С учетом того, что использование Use невозможно для типов, описанных в другом пакете - это единственный способ: везде, где у тебя есть динамическое выделение памяти и ее удаление (через Unchecked_Deallocation) добавить строку, указывающую пул для access-типа. Ну, а чтоб она была одна и та же - описать ее в отдельном пакете.

Вот чего в Аде нет ( напрямую нет, но можно имитировать: Conditional Compilation ) - это условной компиляции, так что когда тебе понадобится убрать отладку - придется еще раз пройти по всем пакетам, и убрать назначение для Storage_Pool.

Можно также воспользоваться The gnatmem tool
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> Закончил отладку (убедился, что утечек нет) - отключай GNAT.Debug_Pools и все use D_Pool.

Жесть какая... А переопределить в том модуле D_Pool на стандартный можно, это какая конструкция делает?

> Вот чего в Аде нет - это условной компиляции

А хоть введут? Блоки вида if true then... - это покрывает только один случай применения условной компиляции.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Цитата
А переопределить в том модуле D_Pool на стандартный можно, это какая конструкция делает?
Можно, но это плохая идея. Дело в том, что глобальные ссылочные типы используют один пул (из пакета System.Pool_Global), локальные - другой (из System.Pool_Local). Что, будешь переопределять всё в один? Я бы не делал этого.

Цитата
А хоть введут? Блоки вида if true then... - это покрывает только один случай применения условной компиляции.
Ну я ж написал, что нет в явном виде. Используй gnatprep - это несложно:

#if DEBUGGING
with GNAT.Debug_Pools; use GNAT.Debug_Pools;
#end if;

with Ada.Unchecked_Deallocation;

with Ada.Text_IO;
with My_Pool;
with MyObj;

procedure Main is

type P_Integer is access Integer;

#if DEBUGGING
for P_Integer'Storage_Pool use My_Pool.D_Pool;
#end if;

procedure Free is new Ada.Unchecked_Deallocation (Integer, P_Integer);

procedure Test is
A, B : P_Integer;
begin
A := new Integer;
B := new Integer;

A.all := 10;
B.all := 20;
Free (A);
end Test;

begin
#if DEBUGGING
GNAT.Debug_Pools.Configure (My_Pool.D_Pool, Raise_Exceptions => False);
#end if;

Test;
MyObj.Test_Recs;

#if DEBUGGING
GNAT.Debug_Pools.Print_Info_Stdout (My_Pool.D_Pool, Display_Leaks => True);
#end if;
end Main;
(аналогичные #if/#end if; во всех файлах, где добавляется тестирование), потом открываешь GPR-файл, и ищешь там описание пакета Compiler. У меня оно, скажем, выглядит так:
   package Compiler is
for Default_Switches ("ada") use ("-gnatVn", "-gnata", "-g", "-gnatf", "-gnat05");
end Compiler;


добавляешь сюда же, в дефолт-опции, еще и предварительную обработку процессором:
   package Compiler is
for Default_Switches ("ada") use ("-gnatVn", "-gnata", "-g", "-gnatf", "-gnat05") & ("-gnateDDEBUGGING=True");
end Compiler;


Сохраняешь файл и полностью пересобираешь проект. Когда отладишь - снова зайдешь сюда, поменяешь в определении ключа True на False, и опять пересоберешь - отладочные строки не будут компилироваться...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> ("-gnateDDEBUGGING=True")

А для этих ключей можно свои имена придумывать? Например "-TestLeaks=True"?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






Разумеется. Ключ -gnateD создает символ для условной компиляции (это аналог Паскалевского ключа /D). Как назовешь - так и будет. Напиши -gnateDTestLeaks=True и будет тебе счастье...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


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

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

Новая версия:

Прикрепленный файл  TEST.rar ( 10.24 килобайт ) Кол-во скачиваний: 426


добавлена фича - если записать в ряд несколько выражений, то считаются все:
Код

Input expression or "exit": sin(pi/3) cos(pi/3)
sin(pi/3) = 8.66025403784438647E-01
cos(pi/3) = 5.00000000000000000E-01

(определять конец текущего выражения тоже вопрос отдельный, короче 95% времени я не выражение разбирал, а определял некорректности, а сам разбор тривиален)


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гость






Ну, в принципе все нормально. Только непонятно, почему ты оставил вот такие повторы:

   function Div(Args: Vector) return F80 is
begin
if integer(Length(Args)) /= 2 then raise Invalid_Expression;
end if;
return Get_Value(Element(Args, 0)) / Get_Value(Element(Args, 1));
end;

function Pow(Args: Vector) return F80 is
begin
if integer(Length(Args)) /= 2 then raise Invalid_Expression;
end if;
return Get_Value(Element(Args, 0)) ** Get_Value(Element(Args, 1));
end;

? То же самое касается и умножения/сложения всех элементов вектора. Это ж одинаковые действия. Зачем дженерики тогда? Делаем так:
   generic with function F(Left, Right : F80) return F80;
function TwoParams (Args : Vector) return F80;

function TwoParams (Args : Vector) return F80 is
begin
if integer(Length(Args)) /= 2 then raise Invalid_Expression;
end if;
return F(Get_Value(Element(Args, 0)), Get_Value(Element(Args, 1)));
end TwoParams;

function Div(Args: Vector) return F80 is
function MyFunc is new TwoParams ("/");
begin
return MyFunc(Args);
end;

function Pow(Args: Vector) return F80 is
function MyFunc is new TwoParams ("**");
begin
return MyFunc(Args);
end;

Еще не совсем понял, почему в Lib_Add_Funcs (при добавлении поддерживаемых функций) ты добавляешь Summ'access, вместо того, чтобы напрямую добавить Add'Access? Зачем вообще этот переходник Summ нужен? Закомментировал его, вроде и без него все нормально. Или я чего-то не увидел? Prod -> Mul тоже можно напрямую заменить...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Summ и Prod пока действительно не нужны. Это я добавил чтобы было отдельно для оператора и отдельно для функции. Ну мало ли в будущем мне понадобится ещё какой-нибудь контроль, и в Add (для оператора) я допишу "аргументов должно быть ровно два". Правда, тогда придётся наоборот вызывать Summ из Add.

Кстати, я вот хотел вместо

function Exp is new TF(Exp);
Add_Func("exp", "Экспонента", Exp'access);

написать

Add_Func("exp", "Экспонента", new TF(Exp)'access);

Мне кажется, что это что-то уже близкое к лямбдам.

> Зачем дженерики тогда? Делаем так:

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

function Div is new TwoParams ("/");
function Pow is new TwoParams ("**");

?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Гость






Цитата
Кстати, для них можно же написать сразу
Ну да, и так тоже можно...

Цитата
Add_Func("exp", "Экспонента", new TF(Exp)'access);
Можешь, конечно, написать, только компилироваться оно не будет. Ада запрещает in-place инстанциацию дженериков. Инстанциация должна проводиться там, где допустимо описание новой подпрограммы. В выражении это недопустимо.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> Можешь, конечно, написать, только компилироваться оно не будет.

Вот и я о том же. А ведь если б разрешили, то такое заворачивать можно было бы!

Сообщение отредактировано: TarasBer -


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Гость






Хм... А чего ты вручную организуешь циклы по контейнерам, вместо того ,чтоб воспользоваться готовыми? Вот тут, например:

Цитата
   procedure Del_Tree(T: in out aFunc_Tree) is

procedure Del_Childs(v: Func_Tree_Vectors.Vector) is
use Func_Tree_Vectors;
T: aFunc_Tree;
begin
for i in First_Index(v) .. Last_Index(v) loop
T := Element(v, i);
Del_Tree(T);
end loop;
end;

begin
if T /= null then
case T.Kind is
when Operator | Func => Del_Childs(T.Childs);
when others => null;
end case;
Free(T);
T := null;
end if;
end;

Да и еще я где-то видел цикл по всему контейнеру... Можно же сделать так:
   procedure Del_Tree(T: in out aFunc_Tree) is

procedure Del_Childs(C : Func_Tree_Vectors.Cursor) is
T : aFunc_Tree := Element ( C );
begin
Del_Tree (T);
end Del_Childs;

begin
if T /= null then
case T.Kind is
when Operator | Func => T.Childs.Iterate (Del_Childs'Access);
when others => null;
end case;
Free(T);
T := null; -- Это можно не делать
end if;
end;

Почему T := null можно не делать? Это будет гарантированно сделано в Unchecked_Deallocation:

Цитата(Ada RM 13.11.2)
Given an instance of Unchecked_Deallocation declared as follows:
procedure Free is new Ada.Unchecked_Deallocation(object_subtype_name, 
access_to_variable_subtype_name);

Procedure Free has the following effect:
1. After executing Free(X), the value of X is null.
2. Free(X), when X is already equal to null, has no effect.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Гость






> Да и еще я где-то видел цикл по всему контейнеру...

Кажется в том месте, где я перегонял массив в вектор? Я ещё спрашивал, нет ли готового метода.
Ну и ещё в Adjust цикл по контейнеру для копирования.

> Можно же сделать так:

Ну буду знать.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #18


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


А как сделать так, чтобы код между

#if Test_Leaks

и

#end if;

не выполнялся?

Я убрал
& ("-gnateDTest_Leaks=True")
, не помогло. Закрыл среду, удалил exe, открыл среду, всё равно не помогло.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #19


Гость






& ("-gnateDTest_Leaks=False")
 К началу страницы 
+ Ответить 
сообщение
Сообщение #20


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Тоже не помогло. Главное, я нажимаю ctrl+F9, а программа пересобирается мгновенно, будто ей не надо все модули из-за новой директивы перекомпилировывать.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

3 страниц V  1 2 3 >
 Ответить  Открыть новую тему 
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 28.03.2024 23:55
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name