pthread导致mysql内存泄漏

时间:2016-02-09 19:07:02

标签: mysql c memory-leaks pthreads

我正在研究一个使用mysql查询数据库的多线程软件,我在调试后不断发现内存泄漏,我不知道导致它们的原因。我跟着mysql dev guidelines以及这个SO answer但是泄漏仍然存在,我能够用这个脚本产生同样的错误:

#include <mysql/mysql.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define DBHOST  "localhost"
#define DBUSER  "#####"
#define DBPSWD  "#######"
#define DBNAME  "testdb"

void die (MYSQL *conn)
{
    fprintf (stderr, "%s\n", mysql_error (conn));
    if (conn != NULL) mysql_close (conn);
    exit (1);
}

MYSQL *DBConnect()
{
    MYSQL *conn = NULL, *res;
    if ((conn = mysql_init (NULL)) == NULL) die (conn);
    res = mysql_real_connect (conn, DBHOST, DBUSER, DBPSWD, DBNAME, 0, NULL, 0);
    if (res == NULL) die (conn);
    return conn;
}

void DBDisconnect (MYSQL *conn)
{
    mysql_close (conn);
    mysql_thread_end();
}

MYSQL_RES *executeQuery (MYSQL *conn, char *query)
{
    MYSQL_RES *result;
    if (mysql_query (conn, query) != 0) die (conn);
    if ((result = mysql_store_result (conn)) == NULL) return NULL;
    return result;
}

int getRecordsCount (MYSQL *conn)
{
    char *query = "SELECT * FROM test";
    MYSQL_RES *results = executeQuery (conn, query);
    int count = mysql_num_rows (results);
    mysql_free_result (results);
    return count;
}

void *handler (void *arg)
{
    MYSQL *conn = DBConnect();
    int n = *((int *) arg);
    sleep (1);
    printf ("Thread %d: count = %d\n", n, getRecordsCount (conn));
    DBDisconnect (conn);
    return NULL;
}

int main (void)
{
    pthread_t threads[10];
    pthread_attr_t attr;
    int i, tCount = 0;

    mysql_library_init (0, NULL, NULL);
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

    for (i = 0; i < 10; i++)
    {
        pthread_create (&(threads[tCount++]), &attr, handler, (void *) &i);
    }
    while (i-- > 0) sleep (2);

    pthread_attr_destroy (&attr);
    pthread_exit (NULL);
    mysql_library_end();

    return 0;
}

生成文件:

CC = gcc
CFLAGS = -Wall -Wextra -pedantic-errors -O2
LIBS = -lmysqlclient -lpthread

all: test
test: test.c
    $(CC) $(CFLAGS) $< $(LIBS) -o $@

Valgrind的:

--15058-- Discarding syms at 0x51cbad0-0x51d26bb in /lib/i386-linux-gnu/libnss_files-2.19.so due to munmap()
==15058== 
==15058== HEAP SUMMARY:
==15058==     in use at exit: 73,872 bytes in 21 blocks
==15058==   total heap usage: 239 allocs, 218 frees, 606,847 bytes allocated
==15058== 
==15058== Searching for pointers to 21 not-freed blocks
==15058== Checked 717,608 bytes
==15058== 
==15058== 16 bytes in 1 blocks are still reachable in loss record 1 of 5
==15058==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15058==    by 0x4095357: my_malloc (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x40913FC: my_error_register (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4071C8C: init_client_errs (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x406E044: mysql_server_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x80488EF: main (in /tmp/test)
==15058== 
==15058== 128 bytes in 1 blocks are definitely lost in loss record 2 of 5
==15058==    at 0x402C109: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15058==    by 0x4096C03: my_thread_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4096ECF: my_thread_global_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4094AF7: my_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x406E014: mysql_server_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x80488EF: main (in /tmp/test)
==15058== 
==15058== 144 bytes in 1 blocks are still reachable in loss record 3 of 5
==15058==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15058==    by 0x4095357: my_malloc (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4090892: init_alloc_root (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4079650: mysql_client_plugin_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x406E049: mysql_server_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x80488EF: main (in /tmp/test)
==15058== 
==15058== 36,792 bytes in 9 blocks are still reachable in loss record 4 of 5
==15058==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15058==    by 0x4095702: my_once_alloc (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x408BF37: ??? (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x408CBA9: ??? (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x438736D: pthread_once (pthread_once.S:120)
==15058==    by 0x408D222: get_charset_by_csname (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4074A39: mysql_init_character_set (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x40759B2: mysql_real_connect (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x8048B15: DBConnect (in /tmp/test)
==15058==    by 0x8048BE9: handler (in /tmp/test)
==15058==    by 0x4381F6F: start_thread (pthread_create.c:312)
==15058==    by 0x4482BED: clone (clone.S:129)
==15058== 
==15058== 36,792 bytes in 9 blocks are still reachable in loss record 5 of 5
==15058==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15058==    by 0x4095702: my_once_alloc (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x408BF56: ??? (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x408CBA9: ??? (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x438736D: pthread_once (pthread_once.S:120)
==15058==    by 0x408D222: get_charset_by_csname (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x4074A39: mysql_init_character_set (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x40759B2: mysql_real_connect (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0)
==15058==    by 0x8048B15: DBConnect (in /tmp/test)
==15058==    by 0x8048BE9: handler (in /tmp/test)
==15058==    by 0x4381F6F: start_thread (pthread_create.c:312)
==15058==    by 0x4482BED: clone (clone.S:129)
==15058== 
==15058== LEAK SUMMARY:
==15058==    definitely lost: 128 bytes in 1 blocks
==15058==    indirectly lost: 0 bytes in 0 blocks
==15058==      possibly lost: 0 bytes in 0 blocks
==15058==    still reachable: 73,744 bytes in 20 blocks
==15058==         suppressed: 0 bytes in 0 blocks
==15058== 
==15058== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==15058== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

如何修复这些内存泄漏?我使用mysql v 5.5,如果这会有所帮助。

1 个答案:

答案 0 :(得分:1)

pthread_exit()函数类似于标准库的exit()函数:它会杀死调用它的线程。它的参数是线程的返回值。

程序的主线程实际上是一个线程,它可以被pthread_exit()杀死。然而,以这种方式杀死主线程是不寻常的,并且期望该函数返回肯定是错误的。在您的特定情况下,在致电mysql_library_end() 后,您对pthread_exit()的呼叫将显示为,因此永远不会执行。正如您所发现的那样,这可以防止mysql库自行清理。