утечка памяти, metallic, 21-Апр-10, 18:12 [смотреть все]Есть демон на Си, он обрабатывает поток netflow, суммирует трафик и складывает в базу. Суть проблемы в том, что подъедает память. С помощью valgrind вычислил пару мелких утечек, устранил. Осталась основная, которую как исправить - не знаю и в чем она заключается - не пойму, т.к. визуально все в порядке. Вот вывод valgrind:==39527== HEAP SUMMARY: ==39527== in use at exit: 7,596,433 bytes in 2,786 blocks ==39527== total heap usage: 46,982 allocs, 44,196 frees, 140,180,473 bytes allocated ==39527== ==39527== 22 bytes in 2 blocks are definitely lost in loss record 3 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0x1113A38: strdup (in /lib/libc.so.7) ==39527== by 0x402C5E: ip_by_username (vpnms_functions.c:264) ==39527== by 0x4030E1: clear_rules (vpnms_functions.c:395) ==39527== by 0x4022B3: StopDaemon (vpnms_functions.c:36) ==39527== by 0x40471A: vpnmsd_nf_thread (vpnmsd_nf_thread.c:78) ==39527== by 0xF994D0: ??? (in /lib/libthr.so.3) ==39527== ==39527== 801 (16 direct, 785 indirect) bytes in 1 blocks are definitely lost in loss record 18 of 32 ==39527== at 0x2458AE: calloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0x401A1A: config_open (config.c:17) ==39527== by 0x40240A: LoadConfig (vpnms_functions.c:84) ==39527== by 0x4054B0: main (vpnmsd.c:233) ==39527== ==39527== 4,088 bytes in 1 blocks are possibly lost in loss record 24 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD298C2: my_once_alloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD29F8B: init_state_maps (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A894: init_available_charsets (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2AAC9: get_charset_by_csname (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3AFE8: mysql_init_character_set (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3CCF4: mysql_real_connect (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0x40290B: exec_query (vpnms_functions.c:167) ==39527== by 0x405523: main (vpnmsd.c:247) ==39527== ==39527== 4,088 bytes in 1 blocks are possibly lost in loss record 25 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD298C2: my_once_alloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD299CA: my_once_strdup (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A34D: add_collation (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD392C8: my_xml_leave (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD39B04: my_xml_parse (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD32F71: my_parse_charset_xml (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A1CB: my_read_charset_file (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A8CF: init_available_charsets (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2AAC9: get_charset_by_csname (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3AFE8: mysql_init_character_set (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3CCF4: mysql_real_connect (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== ==39527== 8,176 bytes in 2 blocks are possibly lost in loss record 27 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD298C2: my_once_alloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD29F6F: init_state_maps (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A894: init_available_charsets (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2AAC9: get_charset_by_csname (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3AFE8: mysql_init_character_set (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3CCF4: mysql_real_connect (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0x40290B: exec_query (vpnms_functions.c:167) ==39527== by 0x405523: main (vpnmsd.c:247) ==39527== ==39527== 12,264 bytes in 3 blocks are possibly lost in loss record 28 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD298C2: my_once_alloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A553: add_collation (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD392C8: my_xml_leave (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD39B56: my_xml_parse (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD32F71: my_parse_charset_xml (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A1CB: my_read_charset_file (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2A8CF: init_available_charsets (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2AAC9: get_charset_by_csname (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3AFE8: mysql_init_character_set (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3CCF4: mysql_real_connect (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0x40290B: exec_query (vpnms_functions.c:167) ==39527== ==39527== 106,080 bytes in 13 blocks are possibly lost in loss record 30 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD22901: my_malloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD2591D: alloc_root (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3B6D9: unpack_fields (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3C646: cli_read_query_result (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3AC6D: mysql_real_query (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0x40295F: exec_query (vpnms_functions.c:174) ==39527== by 0x402B99: username_by_ip (vpnms_functions.c:236) ==39527== by 0x404B58: vpnmsd_nf_thread (vpnmsd_nf_thread.c:166) ==39527== by 0xF994D0: ??? (in /lib/libthr.so.3) ==39527== ==39527== 7,443,072 (143,520 direct, 7,299,552 indirect) bytes in 897 blocks are definitely lost in loss record 32 of 32 ==39527== at 0x24667B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so) ==39527== by 0xD22901: my_malloc (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0xD3A79C: mysql_store_result (in /usr/local/lib/mysql/libmysqlclient.so.16) ==39527== by 0x4029A8: exec_query (vpnms_functions.c:181) ==39527== by 0x402B99: username_by_ip (vpnms_functions.c:236) ==39527== by 0x404B58: vpnmsd_nf_thread (vpnmsd_nf_thread.c:166) ==39527== by 0xF994D0: ??? (in /lib/libthr.so.3) ==39527== ==39527== LEAK SUMMARY: ==39527== definitely lost: 143,558 bytes in 900 blocks ==39527== indirectly lost: 7,300,337 bytes in 1,830 blocks ==39527== possibly lost: 134,696 bytes in 20 blocks ==39527== still reachable: 17,842 bytes in 36 blocks ==39527== suppressed: 0 bytes in 0 blocks ==39527== Reachable blocks (those to which a pointer was found) are not shown. ==39527== To see them, rerun with: --leak-check=full --show-reachable=yes ==39527== ==39527== For counts of detected and suppressed errors, rerun with: -v ==39527== Use --track-origins=yes to see where uninitialised values come from ==39527== ERROR SUMMARY: 470 errors from 19 contexts (suppressed: 24 from 3) Все сводится к ф-ии exec_query, вот ее код:
MYSQL_RES *exec_query(char *query) { MYSQL_RES *res; MYSQL mysql;
if ( 0 == strcasecmp (vpnms_config.vpnms_sql_debug, "yes") ) syslog (LOG_DEBUG, "SQL: %s", query); mysql_init(&mysql); if (!mysql_real_connect(&mysql, vpnms_config.mysql_host, vpnms_config.mysql_username, vpnms_config.mysql_password, vpnms_config.mysql_database, vpnms_config.mysql_port, NULL, 0)) { syslog (LOG_ERR, "Failed to connect to database: Error: %s\n", mysql_error(&mysql)); exit(EXIT_FAILURE); } if ( mysql_real_query(&mysql, query, strlen(query)) ) { syslog (LOG_ERR, "Query failed: Error: %s\n", mysql_error(&mysql)); exit(EXIT_FAILURE); } free(query); res = mysql_store_result(&mysql); mysql_close(&mysql); return res; } Если надо - могу выложить исходники полностью
|
- утечка памяти, Michael, 18:32 , 21-Апр-10 (1)
> >MYSQL_RES *exec_query(char *query) >{ > MYSQL_RES *res;перепишите функцию так, чтобы указатель на MYSQL_RES передавался аргументом и будет вам счастье.
- утечка памяти, metallic, 10:49 , 22-Апр-10 (3)
> >> >>MYSQL_RES *exec_query(char *query) >>{ >> MYSQL_RES *res; > >перепишите функцию так, чтобы указатель на MYSQL_RES передавался аргументом и будет вам >счастье. Не понял, можете подробнее пояснить? >а вы этот res потом освобождаете ? > >mysql_store_result() reads the entire result of a query to the client, allocates >a MYSQL_RES structure, and places the result into this structure. Конечно, после каждого использования ф-ии exec_query
- утечка памяти, Michael, 11:42 , 22-Апр-10 (5)
>Не понял, можете подробнее пояснить? ну вы сами-хоть поняли, что за код вы написали. постараюсь объяснить когда вы вызываете функцию, то под ее переменные выделяется место в стеке, когда функция завершается указателю стека возвращается первоначальное значение, т.е. вы строго говоря возвращаете указатель на область с рандомными данныни. да действительно велика вероятность, что значение в стеке не будет перезаписано к моменту, когда вы используете возвращаемое значение. но расчитывать на это не есть ъорошо
- утечка памяти, guest, 11:59 , 22-Апр-10 (7)
>ну вы сами-хоть поняли, что за код вы написали. постараюсь объяснить >когда вы вызываете функцию, то под ее переменные выделяется место в стеке, >когда функция завершается указателю стека возвращается первоначальное значение, т.е. вы строго >говоря возвращаете указатель на область с рандомными данныни. >да действительно велика вероятность, что значение в стеке не будет перезаписано к >моменту, когда вы используете возвращаемое значение. но расчитывать на это не >есть ъорошо прочувствуйте разницу между char buf[100]; ... return (&buf); и char *buf; ... return (buf);
- утечка памяти, Michael, 12:26 , 22-Апр-10 (8)
>прочувствуйте разницу между >char buf[100]; >... >return (&buf); > >и > >char *buf; >... >return (buf); точно. ступил
- утечка памяти, metallic, 12:59 , 22-Апр-10 (10)
> >>Не понял, можете подробнее пояснить? > >ну вы сами-хоть поняли, что за код вы написали. постараюсь объяснить >когда вы вызываете функцию, то под ее переменные выделяется место в стеке, >когда функция завершается указателю стека возвращается первоначальное значение, т.е. вы строго >говоря возвращаете указатель на область с рандомными данныни. >да действительно велика вероятность, что значение в стеке не будет перезаписано к >моменту, когда вы используете возвращаемое значение. но расчитывать на это не >есть ъорошо т.е. лучше сделать, чтобы ф-ия ничего не возвращала, а лучше передавать ф-ии указатель на res и пусть ф-ия в него пихает данные, а потом завершает свою работу?
- утечка памяти, Michael, 11:46 , 22-Апр-10 (6)
>Конечно, после каждого использования ф-ии exec_query а возвращаемое значение функции mysql_free проверяете?
- утечка памяти, metallic, 13:01 , 22-Апр-10 (11)
> >>Конечно, после каждого использования ф-ии exec_query > >а возвращаемое значение функции mysql_free проверяете? Ну вот пример кода, как я пользуюсь этой ф-ией: query = malloc(256); sprintf(query, "SELECT Subnet_Address, NetMask FROM `subnets`"); res = exec_query(query); rows = mysql_num_rows(res); subnets = calloc(rows + 1, sizeof(struct s_subnets)); while ((row = mysql_fetch_row(res))) { num_subnets++; subnets[num_subnets].address = inet_addr(row[0]); subnets[num_subnets].mask = inet_addr(row[1]); } mysql_free_result(res);
- утечка памяти, Andrey, 07:21 , 22-Апр-10 (2)
а вы этот res потом освобождаете ?mysql_store_result() reads the entire result of a query to the client, allocates a MYSQL_RES structure, and places the result into this structure.
- утечка памяти, guest, 11:19 , 22-Апр-10 (4)
>Есть демон на Си, он обрабатывает поток netflow, суммирует трафик и складывает >в базу. Суть проблемы в том, что подъедает память. Есть вариант, что это разовая утечка из-за автоматического вызова mysql_library_init() при первом mysql_init()
- утечка памяти, metallic, 12:58 , 22-Апр-10 (9)
>>Есть демон на Си, он обрабатывает поток netflow, суммирует трафик и складывает >>в базу. Суть проблемы в том, что подъедает память. > >Есть вариант, что это разовая утечка из-за автоматического вызова mysql_library_init() при >первом mysql_init() Нет, об этом я читал и знаю, что чуть-чуть от библиотеки остается мусора, но он не разрастается, а у меня идет постоянное пожирание оперативной памяти, за сутки может съесть 15Мб
- утечка памяти, guest, 13:40 , 22-Апр-10 (12)
>Нет, об этом я читал и знаю, что чуть-чуть от библиотеки остается >мусора, но он не разрастается, а у меня идет постоянное пожирание >оперативной памяти, за сутки может съесть 15Мб может попробывать >res = mysql_store_result(&mysql); >mysql_close(&mysql); syslog(LOG_DEBUG, "store(%p)", res); >return res; s/mysql_free_resust/my_mysql_free_resust/g void my_mysql_free_resust(MYSQL_RES *res) { syslog(LOG_DEBUG, "free(%p)", res); mysql_free_result(res); } и пытаться понять кто забыл сделать free
- утечка памяти, metallic, 18:41 , 22-Апр-10 (13)
Нашел ошибку, при определенных условиях res не освобождался, поправил, теперь, вроде, все хорошо. Спасибо всем, кто откликнулся.
|