Утечка памяти C ++ - PullRequest
       4

Утечка памяти C ++

45 голосов
/ 27 января 2012

Я только что написал код на C ++, который выполняет некоторые манипуляции со строками, но когда я запускал valgrind, он показывает некоторые возможные утечки памяти. Отладка кода до уровня детализации Я написал простую программу на C ++, похожую на:

#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
        std::string myname("Is there any leaks");
        exit(0);
}

и, пройдя по нему Вальгриндом, я получил:

==20943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 26 from 1)
==20943== malloc/free: in use at exit: 360,645 bytes in 12,854 blocks.
==20943== malloc/free: 65,451 allocs, 52,597 frees, 2,186,968 bytes allocated.
==20943== For counts of detected errors, rerun with: -v
==20943== searching for pointers to 12,854 not-freed blocks.
==20943== checked 424,628 bytes.
==20943== 
==20943== LEAK SUMMARY:
==20943==    definitely lost: 0 bytes in 0 blocks.
==20943==      possibly lost: 917 bytes in 6 blocks.
==20943==    still reachable: 359,728 bytes in 12,848 blocks.
==20943==         suppressed: 0 bytes in 0 blocks.
==20943== Reachable blocks (those to which a pointer was found) are not shown.
==20943== To see them, rerun with: --show-reachable=yes

Затем меня поразило, что мы принудительно вышли (что я и выполнил в своем исходном коде C ++). Теперь проблема в том, что я хочу выйти из программы, так как мой предыдущий старый код ожидает статус выхода нового кода. Например, двоичный файл a.out ожидает выхода из состояния b.out. Есть ли способ избежать утечек памяти, или я действительно должен беспокоиться об утечках памяти, так как программа уже завершает работу в этот момент.

Это также поднимает другой вопрос для меня, такой код вреден?

#include<stdio.h>
#include<cstdlib>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}

Ответы [ 10 ]

65 голосов
/ 27 января 2012

Используйте return 0; вместо exit(0); в конце main.Использование exit обходит выполнение деструкторов.

63 голосов
/ 27 января 2012

Если вы настаиваете на использовании exit():

#include<iostream>
int main(){
    {
        std::string myname("Are there any leaks?");
    }
    exit(0);
}

Кроме того, при возврате из main возвращаемое значение становится кодом завершения приложения.Поэтому, если вы хотите передать код выхода, используйте return exitCode; в main() вместо exit.

Относительно этой части:

Это также вызывает у меня еще один вопросВреден ли такой код?

Да, потому что это привычка программирования BAD .

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

Тем не менее, написание небрежного кода / кода с утечками может превратиться в привычку, поэтому полагаться на ОС для очистки вашего беспорядка - плохая идея.

22 голосов
/ 27 января 2012

Это также поднимает другой вопрос для меня, такой код вреден?

#include<stdio.h>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}

Это не вредно для современных операционных систем, потому что они закроют все ресурсы, принадлежащие процессуавтоматически, когда процесс заканчивается.

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

5 голосов
/ 01 февраля 2012

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

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

Однако в некоторых случаях может быть лучше просто выйти и «протечь».

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

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

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

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

Если вы допустите эту «утечку», операционная система сможет восстановить весь блок памяти, выделенный вашему процессу, гораздо быстрее. Это не заботится о структурах и любой очистке объекта.

http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx

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

4 голосов
/ 27 января 2012

Чтобы избежать утечки памяти, верните состояние с main вместо вызова exit.Если вы возвращаете ноль, вы можете опустить оператор return, если хотите;в этом случае программа выйдет со статусом ноль.

Это также поднимает другой вопрос для меня, является ли такой код вредным?

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

2 голосов
/ 27 января 2012
#include<iostream>
using namespace std;
int main()
{
    {
        std::string myname("Is there any leaks");
    }
    exit(0);
}
1 голос
/ 27 января 2012

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

1 голос
/ 27 января 2012

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

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

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

0 голосов
/ 28 января 2012

Чтобы добавить другое мнение.

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

Если пойти еще дальше и провокационно заявить, явное освобождение памяти при выходе из программы может быть вредным.

  1. Выход из программы занимает больше времени (Вас когда-нибудь раздражало ожидание выхода из программы до выключения компьютера?)
  2. Правильный порядок уничтожения не всегда тривиален, особенно с компонентами сторонних производителей (я помню некоторые программы, которые могут аварийно завершить работу при выходе)
  3. ОС может не позволить вам освободить память после выхода main (*) и вместо этого убить вашу программу

Вы рискуете этим только для того, чтобы заставить Valgrind дать вам конкретный результат? (**)


(*)

#include<iostream>
using namespace std;
std::string myname("Is there any leaks");
int main() {
        exit(0);
}

(**) Ну, конечно, вывод любого анализатора памяти более полезен без «шума». Как насчет только освобождения памяти явно при выходе в режиме отладки?

0 голосов
/ 27 января 2012

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

...