1

私は C++ でデーモンを作成しています。これには、いくつかのイベントを mysql データベースに挿入するという単純なタスクがあります。

top コマンドを実行すると、プロセスのメモリ ニーズが増加することがわかりました。メモリ リークが発生したと考え、Valgrind を使い始めました。

私はこのようにvalgrindを実行しました:

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=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

2 に答える 2

1

関数内でのみ使用しているため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;
}

もちろん、それでもエラー処理は除外されているため、追加し直す必要があります。

于 2013-02-06T08:10:19.100 に答える
1

mysql_init は、mysql_close によって解放される必要があるヒープ割り当てオブジェクトを返します。mysql_init と mysql_close の間の何かが例外をスローした場合、close を呼び出すことはありません。簡単な修正 - mysql_close を catch ブロックに追加します。より良い修正 - RAII について学び、使用してください。

Angew が指摘したように、実際には、mysql_real_connect を呼び出したときに接続がリークしている可能性が高くなります (ログに例外テキストが表示されていない限り)。RAII を使用してこれを回避することもできます。

于 2013-02-06T07:54:33.953 に答える