коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах.
например, выделяете память строго через ваши аллоки, перегружаете new или что то еще более интересное?
что имею в виду под борьбой с кривыми указателями, например:
т.е. такие случаи, когда небезопасно извлекается указатель из чего-то, как в примере.
может, тоже есть какая то система, например, помечать все такие места чем-то, как то так:
-- когда что то непонятное падает, легко поиском по исходникам найти все такие места затем, что когда проект разросся, перелопачивать все исходники в поисках такого проблематично.
спасибо за любые мнения и рекомендации!
Здравствуйте, ksd, Вы писали:
ksd>коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах.
Здравствуйте, ksd, Вы писали:
ksd>коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах. ksd>например, выделяете память строго через ваши аллоки, перегружаете new или что то еще более интересное? ksd>что имею в виду под борьбой с кривыми указателями, например: ksd>
Здравствуйте, ksd, Вы писали:
ksd>коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах. ksd>например, выделяете память строго через ваши аллоки, перегружаете new или что то еще более интересное?
хз, просто культура кода.
Ну например здесь:
ksd>что имею в виду под борьбой с кривыми указателями, например: ksd>
void foo(HANDLE h) {
std::vector<char> v;
DWORD size = GetFileSize(h, 0);
assert(size); <-- чекаем логику ассертом, можно кастомным, который пишет в лог + бросает исключение в релизе
v.resize(size);
ReadFile(h, &v.at(0), ...); <--- at подстелит соломки если строка переедет в другую логику
}
Здравствуйте, ksd, Вы писали:
ksd>спасибо за любые мнения и рекомендации!
Очевидно, умные указатели, контейнеры и свои обёртки для управления ресурсами вроде MutexLock если нет в либе.
Здравствуйте, Kernan, Вы писали:
K>Здравствуйте, ksd, Вы писали:
ksd>>спасибо за любые мнения и рекомендации! K>Очевидно, умные указатели, контейнеры и свои обёртки для управления ресурсами вроде MutexLock если нет в либе.
Это как раз НЕ очевидно. В таких высоко уровневых трудно бывает чтото найти и диагностировать. По мне так лучше чтобы приложение упало и сняло дамп, я пойму где и устраню. Иначе если ошибка произойдет, пусть и логическая, но приложение продолжило работу, по цепочки остальные модули будут работать с ошибкой.
Только Путин, и никого кроме Путина! О Великий и Могучий Путин — царь на веки веков, навсегда!
Смотрю только Соловьева и Михеева, для меня это самые авторитетные эксперты.
КРЫМ НАШ! СКОРО И ВСЯ УКРАИНА БУДЕТ НАШЕЙ!
Здравствуйте, Мёртвый Даун, Вы писали:
МД>Это как раз НЕ очевидно. В таких высоко уровневых трудно бывает чтото найти и диагностировать. По мне так лучше чтобы приложение упало и сняло дамп, я пойму где и устраню. Иначе если ошибка произойдет, пусть и логическая, но приложение продолжило работу, по цепочки остальные модули будут работать с ошибкой.
Для этого придумали ассерты.
Здравствуйте, Мёртвый Даун, Вы писали:
МД>Иначе если ошибка произойдет, пусть и логическая, но приложение продолжило работу, по цепочки остальные модули будут работать с ошибкой.
по какой такой цепочке? откуда она взялась? какова вероятность возникновения такой цепочки? хорошо ли ронять приложение, в котором ошибка в диалоге печати? а если это бекэнд держащий тысячи соединений, надо ронять их все из-за ошибки в одном из них?
Здравствуйте, alpha21264, Вы писали:
A>Здравствуйте, Doom100500, Вы писали:
A>>>Использую valgrind. Да, я живу в Линуксе.
D>>А для винды есть umdh ( да, я на две семьи живу )
A>Даже интересно стало. A>А он только утечки ловит, или выход за границы массива тоже?
Здравствуйте, ksd, Вы писали:
ksd>коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах. ksd>например, выделяете память строго через ваши аллоки, перегружаете new или что то еще более интересное?
Аккуратностью. Например, если я пишу malloc(), то сразу же пишу симметричный ему free(), не откладывая на потом. Кстати, с утечкой файловых хендлов это тоже работает.
Здравствуйте, ksd, Вы писали: A>>хз, просто культура кода. ksd>да! но это не просто культура, а довольно объемный кодекс того, как что кодировать. было бы интересно послушать ваш рассказ про вашу культуру.
Рассказ очень короткий, RAII + smart_pointers, для WinApi он тоже подходит
Здравствуйте, ksd, Вы писали:
ksd>коллеги, кто хочет и может, поделитесь, пожалуйста, вашими методами борьбы с утечками памяти и работой с кривыми указателями в ваших проектах. ksd>например, выделяете память строго через ваши аллоки, перегружаете new или что то еще более интересное?
1. Любые ресурсы, которые в принципе могут "течь", — память, дескрипторы, блокировки, коннекты, парные вызовы
типа acquire/release и т.п., — помещаются в RAII-обертки, либо становятся частью классов, API которых тем или
иным образом гарантирует очистку и который нельзя использовать как-то иначе.
Пожалуй, это один из главных принципов. Если в системе нет сложных и хитроумно связанных друг с другом структур
данных, например графов, то уже одно это гарантирует отсутствие утечек на большей части программного кода.
2. Для более сложных случаев используется паттерн "registry": каждый объект при создании регистрируется в
"реестре", при разрушении удаляет себя из него. Проблемные участки кода, подозреваемые в утечках, проверяются с
помощью registry, чтобы количество объектов до и после выполнения кода было одинаковым.
3. Юнит-тесты и другие всевозможные тесты. Если они действительно пишутся и обеспечивают приемлемое покрытие, то
значительная часть чисто технических ошибок (опечатки, неудачный копи-паст, невнимательность и т.п.) вылавливаются
на самых ранних стадиях. Кстати, "приемлемое покрытие" — это не обязательно 100%, лично мой опыт показывает, что
обычно достаточно проверок базовых и пограничных случаев, а также проверок всяких failure cases (но соглашусь,
что проверять failure cases сложно и очень часто на это "кладут болт").
4. Иногда применяются специальные аллокаторы, особенно когда нужно протестировать какой-нибудь сложный алгоритм,
интенсивно работающий с памятью. В этом случае подаваемый на вход буфер формируется таким образом, чтобы сразу за
его окончанием (или перед первым байтом) была страница памяти с атрибутами защиты 'NoAccess'. Если произойдет
выход за пределы буфера, пусть даже только на чтение, приложение немедленно вылетит с 'Access Violation'.
К сожалению, в чистом виде применять эту технику не всегда возможно (например, из-за требований к выравниванию).
5. Из других средств: ассерты, SAL-аннотации (в основном для драйверного кода), статические и динамические
анализаторы (PREfast, C++ Code Analyzer, Driver Verifier, Application Verifier), checked-сборки Windows...
Ну и конечно, компиляция на максимальном уровне предупреждений (/W4 /WX), отказ от небезопасных языковых
средств (приведения в стиле C, auto::ptr) и так далее.
Из написанного самое важное — это, пожалуй, пункты 1 и 3. То есть, грамотно построенная архитектура приложения
(в которой обычно сильно сложных взаимосвязей нету) с активным использованием RAII, плюс тестовое покрытие.
Использую эти техники очень давно, с утечками памяти и проблемами "сырых указателей" приходилось серьезно
бороться буквально считанные разы. Хотя, может быть, просто повезло
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, alpha21264, Вы писали:
A>>Использую valgrind. Да, я живу в Линуксе.
Pzz>Valgrind — это все же спороб убедиться, что борьба с утечками была успешна, а не способ самой борьбы...
Как-то очень глубокомысленно.
valgrind мне говорит место, где была потеряна память.
Это разве не оно?
Здравствуйте, alpha21264, Вы писали:
Pzz>>Valgrind — это все же спороб убедиться, что борьба с утечками была успешна, а не способ самой борьбы...
A>Как-то очень глубокомысленно. A>valgrind мне говорит место, где была потеряна память. A>Это разве не оно?
Ну, конечно это помогает жить, когда ты не просто знаешь, что память течет, а понимаешь, какая именно. Сильно сужает круг поиска. Но потом все равно надо головой думать. А если заранее не подумать, то потом будет очень сложно думать.
А вот думать заранее, как сделать так, чтобы память не текла — это и есть сама борьба.
Здравствуйте, Pzz, Вы писали:
Pzz>А вот думать заранее, как сделать так, чтобы память не текла — это и есть сама борьба.
Ну, я использую стратегию "освобождается там, где захватывалось".
Если это про объекты, то симметрия конструктор-деструктор.
Но вот если присутсвуют куски чужого кода, тогда valgrind.
Здравствуйте, alpha21264, Вы писали:
Pzz>>А вот думать заранее, как сделать так, чтобы память не текла — это и есть сама борьба.
A>Ну, я использую стратегию "освобождается там, где захватывалось".
Понятно. Под пытками подозреваемый сознался. А то valgrind, valgrind...
Здравствуйте, ksd, Вы писали:
ksd>т.е. такие случаи, когда небезопасно извлекается указатель из чего-то, как в примере.
При всем уважении, в данном примере рассуждать об утечках памяти и кривых указателях несколько преждевременно. Тут все гораздо веселее:
1. Что будет, если GetFileSize выдаст что-нибудь интересное вроде 10^64?
2. Что будет, если между вызовом v.resize и последующим ReadFlile размер последнего изменится?
Поэтому для чтения файлов используются несколько другие паттерны...