2013-02-06 164 views
1

我正在用C++編寫一個守護進程,它有一個簡單的任務,將一些事件插入到mysql數據庫中。用Valgrind檢測內存泄漏

當我運行top命令我看到processe的內存需求的增加,我認爲我有內存泄漏和我開始使用Valgrind的

我的valgrind,因爲這跑:

的valgrind - 工具= MEMCHECK --leak檢查= YES - 顯示,可達= YES --num-呼叫者= 20 --track-FDS = YES ./my_app

我得到以下報告:

==17045== 128 bytes in 1 blocks are definitely lost in loss record 6 of 11 
==17045== at 0x402A629: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==17045== by 0x40AAB63: my_thread_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0) 
==17045== by 0x40AAE43: my_thread_global_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0) 
==17045== by 0x40A92D7: my_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0) 
==17045== by 0x40863FA: mysql_server_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0) 
==17045== by 0x4087B28: mysql_init (in /usr/lib/i386-linux-gnu/libmysqlclient.so.18.0.0) 
==17045== by 0x8049890: write_db(std::string, std::string, std::string) (Listener.cpp:76) 
==17045== by 0x804A692: SocketListener(void*) (Listener.cpp:182) 
==17045== by 0x4052D4B: start_thread (pthread_create.c:308) 
==17045== by 0x4582D3D: clone (clone.S:130) 

功能write_db是這樣的:

void write_db(std::string userid,std::string zona,std::string eveniment) 
{ 
    try 
    { 
    MYSQL * connect; 
    connect = mysql_init(NULL); 
    connect = mysql_real_connect(connect,"127.0.0.1","myusr","mypwd","mytbl",0,NULL,0); 
    std::string stmt = "INSERT INTO t_evenimente(placaid,codev,zona,cand) VALUES(\"" + userid + "\"," + eveniment + ",\"" + zona + "\",NOW())"; 
    std::cout << stmt << std::endl; 
    mysql_query(connect,stmt.c_str()); 
    mysql_close(connect); 
    std::cout << "Inserat eveniment obiectiv " << userid << std::endl; 
    } 
    catch (...) 
    { 
     std::cout <<"Exceptie MYSQL" << std::endl; 
    } 
} 

哪裏是內存泄漏?我正在使用mysql_init並關閉文檔說...可能是一個誤報?

+4

如果mysql_real_connect()返回NULL,就有可能發生內存泄漏。然後你失去了指向由'mysql_init()'返回的對象的指針。 – Angew

回答

2

由於您只在函數內部使用connect,因此不會動態分配它並冒着內存泄漏(很可能是您所看到的那種)的風險。另外,MySQL API是一個C API,不會拋出任何異常讓你捕捉,這將簡化你現在的操作。

void write_db(std::string userid,std::string zona,std::string eveniment) 
{ 
    MYSQL connect; 
    mysql_init(&connect); 
    mysql_real_connect(&connect,"127.0.0.1","myusr","mypwd","mytbl",0,NULL,0); 
    std::string stmt = "INSERT INTO t_evenimente(placaid,codev,zona,cand) VALUES(\"" + userid + "\"," + eveniment + ",\"" + zona + "\",NOW())"; 
    std::cout << stmt << std::endl; 
    mysql_query(&connect,stmt.c_str()); 
    mysql_close(&connect); 
    std::cout << "Inserat eveniment obiectiv " << userid << std::endl; 
} 

當然,這仍然遺漏了錯誤處理,您需要添加回來。

+0

我仍然收到同樣的錯誤! – opc0de

+0

@ opc0de如果錯誤在同一地方,只在第一次調用時顯示,它似乎是MySQL庫內部的東西(即最有可能被視爲誤報)。是否每次顯示一次調用函數或只需要在第一次調用mysql_init時調用一次? –

+0

每一個電話......我認爲是一個誤報 – opc0de

1

mysql_init返回需要由mysql_close釋放的堆分配對象。當mysql_init和mysql_close之間的內容拋出異常時,你永遠不會調用close。快速修復 - 將mysql_close添加到catch塊。更好地解決 - 瞭解/使用RAII。

正如Angew指出的那樣,實際上當您調用mysql_real_connect時(除非您在日誌中看到您的異常文本),您可能更有可能泄漏連接。你也可以使用RAII來避免這一點。

+0

你完全正確。 「部分地」,因爲這個接口是C API,這裏沒有例外。最有可能的是,'mysql_init'和'mysql_close'之間的某些函數失敗並使「句柄」無效。 –

+0

Yeh,我在閱讀Angew的評論後意識到。還在醒來:) – jmetcalfe