libmysqlcppconne准备的语句导致glibc内存损坏
glibc memory corruption with libmysqlcppconn prepared statement
我目前正在Linux上用C++编写一个网络爬虫/蜘蛛,在更新数据库时遇到了一些问题。我是C/C++的新手,仅供参考。
数据库更新是由一个单独的线程执行的(使用pthreads),但如果在main()中执行,也会出现同样的问题,所以我可能很天真地放弃了线程化的东西。
我正在为数据库API使用libmysqlcppconn。
我正在用gcc 4.4.3版本(Ubuntu 4.4.3-4ubuntu5.1)和-O2-Wall-pedantic进行编译,它编译得很干净。
尽管如此,当调用下面的commitChangesToDatabase()函数时,它基本上从std::map(url_queue)中挑选项目,将它们放入std::vector(updates)中,并从原始std::map中擦除所述项目,然后继续迭代std::vector,为向量中的每个项目执行MySQL准备的语句。这就是它失败的地方。
随机选择:
- 没有任何错误输出的崩溃(没有segfault,没有stacktrace,什么都没有)
- 检测到带有glibc内存损坏的崩溃(请参阅此处的输出:http://pastie.org/private/wlkuorivq5tptlcr7ojg)
- 报告MySQL服务器已经离开(发现异常),但仍在尝试(没有崩溃)
我曾尝试将准备好的语句切换为简单的executeUpdate(),但没有成功。在url_queue上的第一个循环中,我尝试消除挑选项目的步骤,而只是在找到要更新的项目时执行更新。
这个应用程序中的其他函数也使用准备好的语句(另一个UPDATE),这很好。这些函数也由单独的线程运行。
我会通过valgrind运行应用程序,但坦率地说,我不理解大部分输出,所以它对我没有多大帮助——但如果有人想要它的输出,请告诉我用哪些选项运行它,我会提供它。
我不知道如何从这里开始。有人知道怎么了吗?
struct queue_item_t {
int id;
int sites_id;
int priority;
int depth;
int handler;
int state; // 0 = Pending, 1 = Working, 2 = Completed, 3 = Checked
double time_allowed_crawl;
bool status;
bool was_redirected;
double time;
double time_end;
double time_curl;
double size;
std::string hash;
std::string url;
std::string file;
std::string host;
};
void commitChangesToDatabase()
{
map< string, queue_item_t >::iterator it, end;
sql::PreparedStatement *pstmt;
int i = 0;
if (!url_queue.size()) {
return;
}
pthread_mutex_lock(&dbCommitMutex);
pthread_mutex_lock(&itemMutex);
cout << "commitChangesToDatabase()" << endl;
pstmt = dbPrepareStatement("UPDATE crawler_queue SET process_hash = NULL, date_crawled = NOW(), url = ?, hash = ? WHERE id = ?");
for (it = url_queue.begin(); it != url_queue.end();)
{
if (it->second.state == 2)
{
pstmt->setString(1, it->second.url);
pstmt->setString(2, it->second.hash);
pstmt->setInt(3, it->second.id);
try {
pstmt->executeUpdate();
++i;
} catch (sql::SQLException &e) {
cerr << "# ERR: SQLException in " << __FILE__;
cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cerr << "# ERR: " << e.what();
cerr << " (MySQL error code: " << e.getErrorCode();
cerr << ", SQLState: " << e.getSQLState() << " )" << endl;
}
url_queue.erase(it++);
}
else {
++it;
}
}
delete pstmt;
cout << "~commitChangesToDatabase()" << endl;
pthread_mutex_unlock(&itemMutex);
pthread_mutex_unlock(&dbCommitMutex);
}
// this function is defined in another file but is written here just to show the contents of it
sql::PreparedStatement *dbPrepareStatement(const std::string &query)
{
return con->prepareStatement(query);
}
编辑:
有些人似乎认为问题出在对url_queue集合的迭代上,但我已经排除了这一点,但注释了数据库上运行的所有内容,而不是迭代。此外,这里的迭代是原始版本的简化(但有效)版本,它从地图中挑选项目,插入向量并从地图中擦除,如下所示,该部分程序运行良好-每当使用数据库时,它仅崩溃。
for (it = url_queue.begin(); it != url_queue.end();)
{
if (it->second.state == 2)
{
update_item.type = (!it->second.was_redirected ? 1 : 2);
update_item.item = it->second;
updates.push_back(update_item);
url_queue.erase(it++);
}
else {
++it;
}
}
编辑2:
valgrind --leak-check=yes
的输出:http://pastie.org/private/2ypk0bmawwsqva3ikfazw
迭代器似乎不必要地递增;第一个在循环体中,也在for语句中。在这段代码中,可以增加end
迭代器,这是一个有问题的操作,可能是问题的根源
以下循环结构更适合这种情况:it = url_queue.begin();
while( it != url_queue.end() ){
//loop body
}
我不认为使用迭代器是个好主意。替换:
else {
++it;
}
发件人:
else continue;
或者直接删除它。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 从检测到 glibc 正常退出 - malloc():内存损坏
- glibc 检测到内存库拉
- 错误消息glibc检测到Malloc():内存损坏(快速)
- libmysqlcppconne准备的语句导致glibc内存损坏
- 检测到glibc;内存损坏
- Glibc mysql_stmt_close释放坏内存
- mmap小尺寸内存,当munmap为glibc时,会将映射内存释放到操作系统
- Glibc检测到错误,可能存在内存泄漏
- 检测到 glibc,但我没有使用动态内存?