The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
утечка памяти, !*! 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);

        • утечка памяти, !*! 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 не освобождался, поправил, теперь, вроде, все хорошо. Спасибо всем, кто откликнулся.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру