Использование C libevent (утечка памяти и оператор удаления)

#c #c #libevent

#c #c #libevent

Вопрос:

У меня есть два файла:

 // event_test_delete.cpp
#include <event.h>

int main() {
        event_base* ev;

        ev = event_init();
        delete ev;

        return 0; 
}
  

И

 // event_test_free.cpp
#include <event.h>
#include <cstdlib>

int main() {
        event_base* ev;

        ev = event_init();
        free(ev);

        return 0; 
}
  

Когда я компилирую ( g event_test_delete.cpp -levent -o event_test_delete.o ) event_test_delete.cpp Я получаю ошибку:

event_test_delete.cpp : В функции ‘int main()’: 
event_test_delete.cpp:8:9: предупреждение: обнаружена возможная проблема при вызове оператора удаления: 
event_test_delete.cpp:5:14: предупреждение: ‘ev’ имеет неполный тип
/usr/include/event.h:211:8: предупреждение: прямое объявление ‘struct event_base’ 
event_test_delete.cpp:8:9: примечание: ни деструктор, ни специфичный для класса оператор delete вызываться не будут, даже если они объявлены при определении класса.

Но когда я компилирую g event_test_free.cpp -levent -o event_test_free.o event_test_free.cpp, я не получаю ту же ошибку, почему?

И второй вопрос (с использованием valgrind), почему происходит утечка памяти?

Вывод Valgrind для первого файла: (почему здесь Mismatched free() / delete / delete [] ?)

azat:~/Desktop/event_test$ valgrind --показать достижимость =да --проверка утечки = полная ./event_test_delete.o 
==4135 == Memcheck, детектор ошибок памяти 
==4135== Авторские права (C) 2002-2010 и GNU GPL'd, Джулиан Сьюард и др.
==4135 == С использованием Valgrind-3.6.0.SVN-Debian и LibVEX; повторите с помощью -h для получения информации об авторских правах 
==4135== Команда: ./event_test_delete.o 
==4135== 
==4135== Несоответствующий free() / delete / удалить []
==4135== при 0x4023881: удаление оператора(void*) (vg_replace_malloc.c:387)
==4135== по 0x8048571: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135 == Адрес 0x4323028 равен 0 байтам внутри выделенного блока размером 944 
==4135== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4135== по 0x4047DA7: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135== 
==4135 == СВОДКА КУЧИ:
==4135== используется при выходе: 672 байта в 5 блоках
==4135 == общее использование кучи: 6 распределений, 1 освобождение, выделено 1616 байт 
==4135== 
==4135 == 8 байт в блоках 1 косвенно теряются в записи о потерях 1 из 5
==4135== в 0x4023F50: malloc (vg_replace_malloc.c:236)
==4135== по 0x4047C7D: event_base_priority_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047E8B: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135 == 12 (4 прямых, 8 косвенных) байт в блоках 1 определенно потеряны в записи потерь 2 из 5 
==4135== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4135== по 0x4047C2D: event_base_priority_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047E8B: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135 == 256 байт в блоках 1 косвенно потеряны в записи о потерях 3 из 5 
==4135== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4135== по 0x4056192: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135 == 384 байта в блоках 1 косвенно потеряны в записи потерь 4 из 5 
==4135== в 0x4023F50: malloc (vg_replace_malloc.c:236)
==4135== по 0x405616C: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135 == 660 (20 прямых, 640 косвенных) байт в блоках 1 определенно потеряны в записи потерь 5 из 5 
==4135== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4135== по 0x4056157: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4135== по 0x8048561: main (в /home/azat/Desktop/event_test/event_test_delete.o) 
==4135== 
==4135 == КРАТКОЕ ОПИСАНИЕ УТЕЧКИ:
==4135 == определенно потеряно: 24 байта в 2 блоках
==4135 == косвенно потеряно: 648 байт в 3 блоках
==4135 == возможно, потеряно: 0 байт в 0 блоках
==4135 == все еще достижимо: 0 байт в 0 блоках
==4135 == подавлено: 0 байт в 0 блоках
==4135== 
==4135== Для подсчета обнаруженных и подавленных ошибок выполните повторный запуск с помощью: -v 
==4135 == СВОДКА ОШИБОК: 3 ошибки из 3 контекстов (подавлено: 28 из 7)

И для второго файла

azat:~/Desktop/event_test$ valgrind --показать достижимость =да --проверка утечки = полная ./event_test_free.o 
==4140== Memcheck, детектор ошибок памяти 
==4140== Авторские права (C) 2002-2010 и GNU GPL'd, Джулиан Сьюард и др.
==4140 == С использованием Valgrind-3.6.0.SVN-Debian и LibVEX; повторите с помощью -h для получения информации об авторских правах 
==4140== Команда: ./event_test_free.o 
==4140== 
==4140== 
==4140== СВОДКА КУЧИ:
==4140== используется при выходе: 672 байта в 5 блоках
==4140 == общее использование кучи: 6 распределений, 1 освобождение, выделено 1616 байт 
==4140== 
==4140 == 8 байт в блоках 1 косвенно теряются в записи о потерях 1 из 5 
==4140== в 0x4023F50: malloc (vg_replace_malloc.c:236)
==4140== по 0x4047C7D: event_base_priority_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047E8B: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x8048531: main (в /home/azat/Desktop/event_test/event_test_free.o) 
==4140== 
== 4140 == 12 (4 прямых, 8 косвенных) байт в блоках 1 определенно потеряны в записи потерь 2 из 5 
==4140== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4140== по 0x4047C2D: event_base_priority_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047E8B: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x8048531: main (в /home/azat/Desktop/event_test/event_test_free.o) 
==4140== 
==4140 == 256 байт в блоках 1 косвенно потеряны в записи о потерях 3 из 5 
==4140== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4140== по 0x4056192: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x8048531: main (в /home/azat/Desktop/event_test/event_test_free.o) 
==4140== 
==4140 == 384 байта в блоках 1 косвенно потеряны в записи потерь 4 из 5 
==4140== в 0x4023F50: malloc (vg_replace_malloc.c:236)
==4140== по 0x405616C: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x8048531: main (в /home/azat/Desktop/event_test/event_test_free.o) 
==4140== 
==4140 == 660 (20 прямых, 640 косвенных) байт в блоках 1 определенно потеряны в записи потерь 5 из 5 
==4140== в 0x402328F: calloc (vg_replace_malloc.c:467)
==4140== по 0x4056157: ??? (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047E46: event_base_new (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x4047EF6: event_init (в /usr/lib/libevent-1.4.so.2.1.3)
==4140== по 0x8048531: main (в /home/azat/Desktop/event_test/event_test_free.o) 
==4140== 
==4140== КРАТКОЕ ОПИСАНИЕ УТЕЧКИ:
==4140 == определенно потеряно: 24 байта в 2 блоках
==4140== косвенно потеряно: 648 байт в 3 блоках
==4140 == возможно, потеряно: 0 байт в 0 блоках
==4140 == все еще достижимо: 0 байт в 0 блоках
==4140 == подавлено: 0 байт в 0 блоках
==4140== 
==4140== Для подсчета обнаруженных и подавленных ошибок выполните повторный запуск с помощью: -v 
==4140 == СВОДКА ОШИБОК: 2 ошибки из 2 контекстов (подавлено: 28 из 7)

Комментарии:

1. Можете ли вы показать нам реализацию event_init() . Обратите внимание, что это delete может быть вызвано только в памяти, выделенной new . Похоже, что valgrind указывает вам на эту ошибку в первом файле. Возможно, компилятор делает то же самое.

2. event_init() реализует в libevent

Ответ №1:

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

С другой стороны, valgrind, кажется, говорит, что память выделяется с использованием malloc и calloc. В этом случае вам не следует использовать delete вообще, но возможно free .

Во втором случае, при использовании free , valgrind по-прежнему жалуется на утечки памяти. Одна из возможностей здесь заключается в том, что объект event содержит указатели на другие выделения, которые также необходимо освободить.

В этом случае должна быть другая функция, event_free или event_release которую вы должны вызвать, чтобы вернуть объект event. У вас есть один из них?

Комментарии:

1. event_init является libevent функцией, monkey.org /~provos/libevent/doxygen-1.4.10

2. memcached ( memcached.org ) мы тоже используем libevent , но я пытаюсь профилировать его с помощью valgrind , и утечек памяти нет. Но в примере, который дает мне libevent официальную страницу, есть утечки памяти. Но вопрос в том, как я могу избежать этой утечки памяти в моем случае?

3. @azat — Ссылка ведет на типичную страницу doxygen, она описывает каждую функцию независимо, но ничего не говорит о том, в каком порядке вы должны их вызывать. Но поскольку вы получаете сообщение event_base* от event_init() , можно предположить, что event_base_free было бы неплохо снова его освободить. Но это всего лишь предположение! Я не знаю наверняка.

Ответ №2:

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

Второй вопрос: смотрите комментарий под вопросом. Нам нужно знать, что делает event_init и как он выделяет память для информирования о существующих утечках памяти. Тем не менее, хороший совет: доверяйте Valgrind.

Комментарии:

1. смотрите комментарии к следующему ответчику

Ответ №3:

Libevent написан не на C , и, следовательно, он не использует деструкторы. Вы никогда не должны использовать delete для кода, который не был выделен с помощью new .

Если вы прочитали руководство по libevent в разделе «освобождение базы событий», там указано, что вы должны использовать:

 void event_base_free(struct event_base *base);
  

Кроме того, event_new функция для выделения базы событий устарела (поскольку она не потокобезопасна), вам следует вместо этого использовать:

 struct event_base *event_base_new(void);