我正在研究一个使用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,如果这会有所帮助。
答案 0 :(得分:1)
pthread_exit()
函数类似于标准库的exit()
函数:它会杀死调用它的线程。它的参数是线程的返回值。
程序的主线程实际上是一个线程,它可以被pthread_exit()
杀死。然而,以这种方式杀死主线程是不寻常的,并且期望该函数返回肯定是错误的。在您的特定情况下,在致电mysql_library_end()
后,您对pthread_exit()
的呼叫将显示为,因此永远不会执行。正如您所发现的那样,这可以防止mysql库自行清理。