过去一个月我一直在摸不着头脑,我仍然无法弄清楚发生了什么。
问题是我在使用Visual Studio 2005编译的Windows Server 2008上运行的C ++应用程序上存在非常严重的内存泄漏。这是一个托管项目。应用程序从大约5-6MB开始(根据任务管理器)并开始出现大约200MB标记的故障症状。我知道任务管理器是一个粗糙的工具,但考虑到泄漏的规模,似乎可以使用。
我已将问题缩小到MySQL数据库交互。如果应用程序不与数据库交互,则不会泄漏内存。
所有数据库交互都使用mysql ++。我已经按照tangentsoft.net上的手册页中的构建说明进行操作。
我们已经评估了线程安全的代码(也就是说,我们确保每个线程只使用来自该线程的mysqlpp对象,而不是其他线程)并检查以确保为使用'new创建的任何动态生成的对象调用所有析构函数”。
在互联网上查看我一直看到来自mysqlpp类用户的各种报告,表明某处有泄漏。特别是,讨论了当使用mysqlpp时Win C API如何泄漏:
http://www.phpmarks.com/6-mysql-plus/ffd713579bbb1c3e.htm
这个讨论似乎在一个修复中得出结论,然而,当我在我的应用程序中尝试修复时,它仍然会泄漏。
我实现了上面线程中引用的应用程序版本,但是添加了手册页的一些建议:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
while (true)
{
//Initialise MySQL API
mysql_library_init(0, NULL, NULL);
Sleep(50);
//Connect to Database.
mysqlpp::Connection c;
c.connect("myDatabase","localhost","username","password");
Sleep(50);
//Disconnect from Database
c.disconnect();
Sleep(50);
//Free memory allocated to the heap for this thread
c.thread_end();
Sleep(50);
//Free any memory allocated by MySQL C API
mysql_library_end();
Sleep(50);
}
return 1;
}
我添加Sleep(50)只是为了限制循环的每个阶段,以便每个函数都有时间“安定下来”。我知道这可能没有必要,但至少这样我可以将其作为一个原因消除。
然而,这个程序泄漏得非常快(每小时约1mb)。
我在一些地方看到过与我相似的问题,没有得出任何结论:(
所以我并不孤单。在我看来,mysqlpp类具有实用性的声誉,因此必须非常强大。既然如此,我仍然看不出我做错了什么。有没有人对Visual Studio 2005有一些mysqlpp的经验可能会解决这个问题?
干杯, 亚当。
修改
我使用指针创建了另一个示例,以防c在循环中重复:
//LEAKY
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
mysqlpp::Connection * c;
while (true)
{
mysql_library_init(0, NULL, NULL);
c = new mysqlpp::Connection;
Sleep(50);
c->connect("myDatabase","localhost","username","password");
Sleep(50);
c->disconnect();
Sleep(50);
c->thread_end();
Sleep(50);
mysql_library_end();
Sleep(50);
delete c;
c = NULL;
}
return 1;
}
这也泄漏了。然后我创建了一个基于此代码的控件示例,它根本不泄漏:
//NOT LEAKY
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
char * ch;
while (true)
{
mysql_library_init(0, NULL, NULL);
//Allocate 4000 bytes
ch = new char [4000];
Sleep(250);
mysql_library_end();
delete ch;
ch = NULL;
}
return 1;
}
请注意,我还在这里留下了对MySQL C API的调用,以证明它不是泄漏的原因。然后,我使用指针创建了一个示例,但没有连接/断开连接的调用:
//NOT LEAKY
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
mysqlpp::Connection * c;
while (true)
{
mysql_library_init(0, NULL, NULL);
c = new mysqlpp::Connection;
Sleep(250);
mysql_library_end();
delete c;
c = NULL;
}
return 1;
}
这不会泄漏。
所以不同之处仅在于使用了mysqlpp :: connect / disconnect方法。我将深入研究mysqlpp类本身并试着看看它是什么。
干杯, 亚当。
修改
以下是进行检查的泄密代码示例。
//LEAKY
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
mysqlpp::Connection * c;
while (true)
{
mysql_library_init(0, NULL, NULL);
c = new mysqlpp::Connection;
Sleep(50);
if ( c->connect("myDatabase","localhost","username","password") == false )
{
cout << "Connection Failure";
return 0;
}
Sleep(50);
c->disconnect();
Sleep(50);
c->thread_end();
Sleep(50);
mysql_library_end();
Sleep(50);
delete c;
c = NULL;
}
return 1;
}
干杯, 亚当。