Как подключить fastmm delphi

Дневник Дмитрия Тимохова

вторник, 6 марта 2007 г.

Введение

О чем речь

Предполагается, что FastMM используется для отладки приложения. Это важно, т.к. FastMM, работающий в режиме отладки, серьезно тормозит выполнение программы.

Версии дельфи, для которых применим материал

История FastMM

По сравнению с ранее существовавшим манагером FastMM обладает следующими достоинствами:

Естественно FastMM включается не только в программы, создаваемый разработчиком, но и в саму IDE. Насколько я понимаю одной из причин резкого ускорения работы IDE при переходе от BDS2005 к BDS2006 был именно FastMM.

Проблемы

Проблема в том, что:

При этом никто не машает скачать полную версию FastMM и заменить ею «штатный» FastMM, который есть в Delphi, настроив заменяющий FastMM таким образом, чтобы получать максимальную выгоду от сервисных функций в процессе отладки.

Использование FastMM

Где брать

Далее идете по ссылке Download FastMM. и скачиваете версию 4.x. В настоящий момент последней версией является 4.78.

Как устанавливать

Устанавливать собственно и не надо ничего. Есть три файла, которые вам необходимы:

NB Как использовать FastMM для DLL я не знаю, ибо не разбирался. Но в файле FastMM4Options.inc есть очень много комментариев по поводу настройки FastMM. Скорее всего там можно выяснить этот вопрос.

Настройка FastMM

Настройки проекта

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

Цель примера показать, что в стеке вызовов, приведшего к утечке памяти будут методы TMyClass.Execute() и TMyClass.fProcess() с точным указанием номера строки исходного кода.

В частности будет представлена следующая информация:

Видно, что здесь, во-первых, указан класс, объект которого «утек», во-вторых, указан стек вызовов, приведший к утечке.

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

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

В отладочном режиме (т.е. если включена опция условной компиляции FullDebugMode ) FastMM при удалении объекта «портит» память, занимаемую ранее объектом, таким образом, что при следующей попытке вызывать виртуальный метод удаленного объекта FastMM возбуждает исключение.

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

Ниже представлен пример отслеживания момента повторного удаления объекта (деструктор тоже виртуальный метод).

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

Во-вторых, в файле Project1_MemoryManager_EventLog.txt можно посмотреть:

Источник

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

24 мая 2009 г.

Ищем утечки памяти

Когда новичок загорается идеей поиска утечек памяти (или оптимизации использования памяти), он обычно открывает Диспетчер Задач и смотрит на своё приложение и колонку «Память» напротив него:


И всё бы ничего, но потом он замечает, что колонка эта очень странно себя ведёт даже на простом приложении: память не уменьшается при закрытии форм, но почему-то пропадает при сворачивании приложения и т.п.

READ  Как подключить внешний gps приемник к смартфону на андроид

Вот снимок стандартного Диспетчера Задач и более продвинутого Process Explorer со всеми колонками «памяти»:


Не правда-ли, большой разброс по значениям?

Так что давайте выкинем на время Диспетчер Задач и вернёмся к нашему Паскалю. Как в Delphi осуществляется управление памятью? Ранее я уже говорил о наличии кода, который осуществляет централизованное управление памятью. Этот код называется менеджером памяти. Это значит, что искать утечки памяти не очень сложно, т.к. мы можем легко перехватить любые выделения и освобождения памяти, просто подставив свой «менеджер памяти», который будет просто заглушкой. Он не будет реально работать с памятью, перенаправляя запросы старому (настоящему) менеджеру памяти программы, а вместо этого он будет просто вести учёт памяти.

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

Delphi

Окей, даже в Delphi «из коробки» есть базовая возможность диагностики, так что вы можете как минимум проверить наличие утечек памяти без использования сторонних утилит. Правда, если вы увидите утечку, то чтобы найти источник проблемы, вам всё же придётся воспользоваться чем-то ещё. Ну да ладно.

Окей, в старом менеджере памяти у нас в распоряжении есть глобальные переменные AllocMemCount и AllocMemSize (кол-во и суммарный размер выделенных блоков). Таким образом, чтобы сделать простейшую проверку на утечки памяти, вам нужно использовать такой простой модуль:
Не забудьте, что подключать его нужно самым первым в dpr-файле (оба пункта важны принципиально). Если при выполнении программы у вас будет утечка памяти, то при закрытии программы вам будет показано сообщение.

EurekaLog

В любом случае, для её включения нужно поставить флажок «Catch memory leaks» на вкладке «Advanced options»:


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

Несколько под-опций на всё той же вкладке «Advanced options» контролируют поведение проверок утечек памяти.

Опция «Hide Borland leaks» пытается опознать и скрывать утечки памяти, вызванные недочётами в коде RTL/VCL Delphi. При выключенной опции вы можете получать отчёт об утечке, даже если в вашем коде её нет. Например, код может создать глобальный объект, но никогда не удалять его, в расчёте на то, что память будет освобождена при выходе из приложения. Хотя, строго говоря, это не является программистской ошибкой, это, тем не менее, ошибка проектирования, т.к. она затрудняет анализ приложения на настоящие утечки памяти.

Опция «Free All Memory» говорит сама за себя: надо ли освобождать память для этих самых утечек. В большинстве случаев нет никакой разницы, т.к. при выходе из программы вся память всё равно будет освобождена. В основном эта опция используется для решения проблем совместимости со сторонним кодом.

FastMM

FastMM также имеет неплохие возможности по диагностике утечек памяти. К сожалению, встроенная в Delphi версия не обладает полным функционалом, поэтому вам всё равно придётся скачать и установить полную версию FastMM.

Из-за этого FastMM в режиме отладки слабо подходит для использования вне окружения для разработки: всё-таки вам придётся таскать за собой отдельную DLL, да плюс ещё замедление работы. Поэтому оптимальным вариантом будет тестирование программы с полным режимом отладки FastMM при разработке, а поставлять программу стоит с выключенной опцией поиска утечек памяти, либо же использовать функциональность EurekaLog. Она выглядит более скромно, чем аналогичная функциональность в FastMM, зато и более пригодна к использованию на машина конечных пользователей.

READ  Палка для селфи как подключить флай

Прежде, чем вы сможете использовать FastMM в своей программе, вам осталось сделать ещё одну вещь: добавить в программу один из вариантов отладочной информации. Если в случае с EurekaLog отладочная информация генерировалась и добавлялась в программу автоматически, а в случае с Delphi она была просто не нужна (т.к. там были простые проверки, не было стеков вызовов), то для FastMM её нужно добавлять вручную. Отладочная информация используется библиотекой FastMM_FullDebugMode.dll при построении отчёта для получения информации об адресах памяти в вашей программе. Если отладочная информация будет недоступна, то в отчётах об ошибках вы увидите только безликие адреса, а никаких Button1Click там не будет.

В первом случае будет генерироваться отдельный файл, который вам нужно будет таскать с программой, во втором случае отладочная информация будет включаться в сам исполняемый модуль.


Скорее всего, вы захотите включить все три опции.

Вот как выглядит одна полная запись об утечке памяти в лог-файле:

This block was allocated by thread 0x4F8C, and the stack trace (return addresses) at the time was:
403206 [System][System.@GetMem]
4CC5B7 [Unit15.pas][Unit15][Unit15.B][35]
4CC5C4 [Unit15.pas][Unit15][Unit15.A][39]
4CC5DC [Unit15.pas][Unit15][Unit15.TForm15.FormCreate][43]
4C0CCB [Forms][Forms.TCustomForm.DoCreate]
4C0913 [Forms][Forms.TCustomForm.AfterConstruction]
4C08E8 [Forms][Forms.TCustomForm.Create]
4CA539 [Forms][Forms.TApplication.CreateForm]
4CD986 [Project14][Project14.Project14][14]
75B94911 [BaseThreadInitThunk]
770FE4B6 [Unknown function at RtlInitializeExceptionChain]

The block is currently used for an object of class: TTest

The allocation number is: 3814

MemProof/AQTime

Я не буду рассматривать использование этих инструментов здесь, т.к. это отдельная большая тема. Интересующихся, отправляю к этой статье.

Замечу, что они позволяют справляться даже с такими проблемами, как неявные утечки памяти. Например, объекты могут не освобождаться вовремя, скапливаясь в каком-либо глобальном списке. Они реально не используются в программе и их число со временем растёт, но, тем не менее, они не считаются за утечку памяти, т.к. список вместе со всеми объектами корректно удаляется при выходе из программы.

Не только утечки.

Но об этом мы поговорим в следующий раз.

В любом случае, у вас всегда есть вариант просто переписать код 😉

Источник

Менеджеры памяти для Lazarus/FPC и парсинг JSON

Когда только изучать Lazarus и FPC, то встречал на просторах Интернет достаточно много информации по поводу менеджера памяти Free Pascal. Причем, информация эта носила самые разные оттенки – от крайне негативных отзывов (менеджер памяти тормозной), до положительных (спроектирован грамотно, лучше для разработки под разные ОС не придумать) и нейтральных (хорошо спроектирован, но иногда подводит скорость). Встречал и альтернативные менеджеры памяти для Lazarus/FPC, но до их использования как-то дошел.

На сегодняшний день мой “круг интересов” в плане разработки ограничен небольшими утилитами в области моей профессиональной деятельности, где сверхбыстрые математические вычисления и парсинг JSON размером в 6 Гб занимают, наверное, 0,0001% от всей работы. Однако, в комментариях к статье “Работа с JSON в Lazarus/Free Pascal” Kazantsev Alexey справедливо предположил, что на скорость парсинга JSON может повлиять замена родного для FPC менеджера памяти на менеджер памяти от Synopse/ mORMot2. И мне стало интересно: как сильно повлияет замена менеджера памяти в Lazarus/FPC на скорость работы парсера JSON?

Что имеем на старте

На старте имеем файл с JSON-объектом, в котором содержится 10 массивов по 500 000 элементов каждый. Размер файла – 60 Мб.

Менеджеры памяти для Lazarus/FPC:

Ради “спортивного” интереса распарсим тот же JSON в Delphi с менеджером памяти FastMM5 о котором узнал из блога “ИТ-записки Чорнага кашака“.

Результаты

Код для теста оставил тот же самый, что и в статье про JSON в Lazarus/FPC:

READ  Телевизор сони как подключить цифровое тв

Родной менеджер памяти Free Pascal

Что показал “Диспетчер задач”

Учитывая, что потребление памяти постоянно увеличивалось в процессе парсинга, скриншот постарался сделать в момент, когда разбор JSON подходил к финалу, т.е. примерно на 20-21 секунде теста.

Как и ожидалось, результат был практически тот же самый, что и в предыдущий раз:

Примерно 21 секунда на разбор JSON, включая создание и уничтожение необходимых объектов.

Подключаем модуль cmem первым в uses:

Начинаем тестировать парсинг JSON и…я честно прождал отклика программы минут пять. Вот что показывал “Диспетчер задач” при запуске программки:

Вот, что показал “Диспетчер задач”, когда я устал ждать хоть какого-то результата:

Спустя пять минут потребление памяти начало уменьшаться примерно на 1-1,5 Мб/с. Решил дождаться результата хотя бы одного теста и дождался:

827,5 секунд!

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

fpcx64mm

Постарался отловить момент максимального потребления памяти:

Но, по-моему, в какой-то момент проскакивало значение порядка 450 Мб. Результаты теста получились следующие:

Возможно, что, используя настройки этого менеджера памяти, можно получить ещё более впечатляющий результат, но то,что результат оказался в 10 раз лучше, чем с родным менеджером памяти Free Pascal уже о чем-то да говорит.

Дефолтный менеджер памяти в Delphi 10.3 Rio

Код теста взял из вот этой статьи про JSON в Delphi.

Что показывал диспетчер задач:
Результат работы в миллисекундах:

FastMM5 в Delphi 10.3 Rio

Скачивал FastMM5 вот отсюда. Подключил FastMM5 первым модулем в uses.

Результат в Диспетчере задач

Результат работы в миллисекундах:

Возможно FastMM5 где-то и работает быстрее, но родной дефолтный менеджер Delphi 10.3 на миллисекунды, но оказался по-быстрее при парсинге JSON.

Для наглядности ниже приведена гистограмма с информацией по всем менеджерам памяти в Delphi и FPC и таблица с результатами

CMem убрал из гистограммы, так как с ним все остальные столбцы превращались в точку. Также, для CMem во всех случаях показан один и тот же результат, так как ждать 2 часа пока программка закончит работу как-то не хотелось.

№ теста Lazarus/FPC
Delphi
fpc cmem fpcx64mm FastMM4 FastMM5
1 21465 827500 2207 910 989
2 21590 827500 2209 910 986
3 21324 827500 2216 901 979
4 21475 827500 2196 915 988
5 21414 827500 2188 911 982
6 21501 827500 2194 912 991
7 21469 827500 2198 927 989
8 21730 827500 2189 921 984
9 21504 827500 2195 914 984
10 21759 827500 2205 917 984

По результатам могу сказать, что предложенный Алексеем менеджер памяти оказался довольно шустрым, особенно на фоне родного для fpc и не родного cmem. Да, парсинг JSON в Delphi всё равно оказался быстрее, но, при этом также надо учитывать и то, что время засекалось от момента создания объекта до полного уничтожения. В Delphi – это один объект TJsonObject, в Lazarus же, чтобы избежать утечки памяти при работе с TJsonParser необходимо “убивать” два объекта – сам парсер и TJsonData, который создается при парсинге JSON. Что касается менеджера от Synopse, то планирую его также протестировать на одной программке под Linux, в которой происходит очень много математических вычислений – от сложения и вычитания, до решения линейных уравнений и возведения в степени типа 3/7, 4/3 и т.д.

Источник

Поделиться с друзьями
Как подключить и установить...
Adblock
detector