Как записывать маллоки

Это немного гипотетически и сильно упрощено, но ...

Предположим, что программа будет вызывать функции, написанные третьими сторонами. Эти стороны можно считать не враждебными, но нельзя считать «компетентными». Каждая функция будет принимать некоторые аргументы, иметь побочные эффекты и возвращать значение. У них нет состояния, пока они не запущены.

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

Это возможно? Это практично?

p.s. Для меня важной частью является обеспечение того, чтобы никакие распределения не сохранялись, поэтому способы устранения утечек памяти без выполнения этого для меня бесполезны.

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
1 225
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Разве вы не можете просто заставить их выделить всю свою память в стеке? Таким образом, будет гарантировано освобождение после выхода из функции.

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

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

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

Во-первых, вы должны предоставить точки входа для malloc() и free() и других пользователей. Поскольку этот код уже скомпилирован (верно?), Вы не можете полагаться на #define для перенаправления.

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

Самый быстрый способ - это нет регистрации вообще.. Если объем используемой ими памяти ограничен, почему бы не выделить заранее всю «кучу», которая им когда-либо понадобится, и не написать из нее распределитель? Затем, когда это будет сделано, освободите всю "кучу", и все готово! Вы можете распространить эту идею на несколько куч, если это будет сложнее.

Если вам действительно нужно «вести журнал», а не создавать свой собственный распределитель, вот несколько идей. Во-первых, используйте хеш-таблицу с указателями и внутренней цепочкой. Другой вариант - выделить дополнительное пространство перед каждым блоком и поместить туда свою собственную структуру, содержащую, скажем, индекс, в вашу «таблицу журналов», а затем сохранить свободный список записей таблицы журналов (в виде стека, чтобы получить бесплатный или вернуть свободный - O (1)). Это требует больше памяти, но должно быть быстрым.

Это практично? Я думаю, что это так, пока приемлемо скоростное попадание.

Поскольку вы беспокоитесь об утечках памяти и говорите о malloc / free, я предполагаю, что вы находитесь на C. Я также предполагаю, основываясь на вашем вопросе, что у вас нет доступа к исходному коду сторонней библиотеки.

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

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

Вы не указываете операционную систему или среду, в этом ответе предполагается, что Linux, glibc и C.

Вы можете установить __malloc_hook, __free_hook и __realloc_hook, чтобы они указывали на функции, которые будут вызываться из malloc (), realloc () и free () соответственно. Существует справочная страница __malloc_hook, на которой показаны прототипы. Вы можете добавить выделение дорожек в эти хуки, а затем вернуться, чтобы позволить glibc обрабатывать выделение / освобождение памяти.

Похоже, вы хотите освободить любые живые выделения, когда возвращается сторонняя функция. Есть способы, чтобы gcc автоматически вставлял вызовы при каждом входе и выходе из функции с помощью -finstrument-functions, но я думаю, что это было бы неэлегантно для того, что вы пытаетесь сделать. Можете ли вы иметь собственный код для вызова функции в вашей библиотеке отслеживания памяти после вызова одной из этих сторонних функций? Затем вы можете проверить, есть ли какие-либо выделения, которые сторонняя функция еще не освободила.

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

При этом, если ваша сторонняя библиотека имеет обширные распределения, более чем непрактично отслеживать это через ведение журнала. Если вы работаете в среде Windows, я бы посоветовал использовать такой инструмент, как Purify [1] или BoundsChecker [2], который должен уметь обнаруживать утечки в ваших сторонних библиотеках. Инвестиции в инструмент должны окупиться за счет сэкономленного времени.

[1]: http://www-01.ibm.com/software/awdtools/purify/ Очистить

[2]: http://www.compuware.com/products/devpartner/visualc.htm BoundsChecker

Если у вас есть лишние деньги, подумайте об использовании Purify для отслеживания проблем. Он творит чудеса и не требует исходного кода или перекомпиляции. Существуют также другие доступные библиотеки malloc для отладки, которые дешевле. Я припоминаю одно имя - Electric Fence. Тем не менее, отладочные хуки, упомянутые Дентоном Джентри, тоже кажутся интересными.

Если вы слишком бедны для Purify, попробуйте Valgrind. Это намного лучше, чем было 6 лет назад, и намного легче погрузиться в него, чем Purify.

Да, valgrind тоже неплохо работает. Спасибо за напоминание.

Jonathan Leffler 21.10.2008 08:14

Microsoft Windows предоставляет (используйте SUA, если вам нужен POSIX), вполне возможно, самую продвинутую инфраструктуру кучи + (другой API, использующий кучу) на сегодняшний день.

ловушки отладки __malloc () и связанные с ними интерфейсы отладки CRT удобны для случаев, когда у вас есть исходный код для тестов, однако они часто могут пропускать выделение стандартными библиотеками или другим связанным кодом. Это ожидается, поскольку они являются инфраструктурой отладки кучи Visual Studio.

gflags - это очень полный и подробный набор возможностей отладки, который уже много лет включен в Windows. Наличие расширенной функциональности для вариантов использования только исходного кода и двоичного кода (поскольку это инфраструктура отладки кучи ОС).

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

umdh - это инструмент, который может помочь оценить статус в различных контрольных точках, однако данные постоянно накапливаются во время выполнения цели, o это не просто остановка отладки контрольной точки в традиционном контексте. Кроме того, ПРЕДУПРЕЖДЕНИЕ, последний раз я проверил, по крайней мере, общий размер кольцевого буфера, в котором хранится информация о стеке, для каждого запроса несколько невелик (64k записей (записи + стек)), поэтому вам может потребоваться быстро сбросить дамп для пользователей с большой кучей . Есть и другие способы доступа к этим данным, но umdh довольно прост.

ПРИМЕЧАНИЕ есть 2 режима;

  1. РЕЖИМ 1, umdh {-p: идентификатор-процесса | -pn: имя процесса} [-f: имя файла] [-g]
  2. РЕЖИМ 2, umdh [-d] {Файл1} [Файл2] [-f: Имя файла]

    Я не знаю, какое безумие охватило разработчика, который решил чередовать спецификатор аргумента -p: foo и голый порядок аргументов, но это может немного запутать.

SDK для отладки работает с рядом других инструментов, memsnap - это инструмент, который, по-видимому, ориентирован на утечку памяти и тому подобное, но я не использовал его, ваш пробег может отличаться.

Выполнять gflags без аргументов для режима пользовательского интерфейса, + arg и / args также являются «режимами» разные.

В Linux я успешно использовал mtrace(3) для журналирования распределения и освобождения. Его использование так же просто, как

  1. Измените свою программу так, чтобы она вызывала mtrace(), когда вам нужно начать трассировку (например, в верхней части main()),
  2. Задайте в переменной среды MALLOC_TRACE путь к файлу, в котором должна быть сохранена трассировка, и запустите программу.

После этого выходной файл будет содержать что-то вроде этого (отрывок из середины, чтобы показать неудачное выделение):

@ /usr/lib/tls/libnvidia-tls.so.390.116:[0xf44b795c] + 0x99e5e20 0x49
@ /opt/gcc-7/lib/libstdc++.so.6:(_ZdlPv+0x18)[0xf6a80f78] - 0x99beba0
@ /usr/lib/tls/libnvidia-tls.so.390.116:[0xf44b795c] + 0x9a23ec0 0x10
@ /opt/gcc-7/lib/libstdc++.so.6:(_ZdlPv+0x18)[0xf6a80f78] - 0x9a23ec0
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668ee49] + 0x99c67c0 0x8
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668f14f] - 0x99c67c0
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668ee49] + (nil) 0x30000000
@ /lib/libc.so.6:[0xf677f8eb] + 0x99c21f0 0x158
@ /lib/libc.so.6:(_IO_file_doallocate+0x91)[0xf677ee61] + 0xbfb00480 0x400
@ /lib/libc.so.6:(_IO_setb+0x59)[0xf678d7f9] - 0xbfb00480

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