1.问题:
最近正在测试写的QT应用程序,QT程序运行在S3C2440板子上的linux系统中,测试的过程中发现一个奇怪的问题,QT程序占用内存一次比一次大。比如第一次开机QT应用程序运行内存为30M,在运行一段时间后增加到33M,此时我将板子断电。第二次上电重启,怪事发生了,此时运行内存达到了34M,运行一段时间后达到37M。依次类推,最后QT程序因为占用内存过大被linux系统直接杀掉了,后面直接就起不来了。这个问题我百思不得其解,按理即使有内存泄露,断电重启它应该也会复原啊,为何内存却一次比一次大呢?
2.原因:
经过多天的查找终于找到了故障点,原来是因为我程序中使用了SQLite数据库导致的。具体的原因是,我在QT程序中使用SQLite数据库存取历史数据,存取的历史数据是由下位机传上来的,每5秒存一次,这样每天存取的数据量达到17280条,量比较大。而导致内存一次比一次大的根本原因就在于我获取数据库最后一条记录的操作方式,由于我使用文件号的形式存取数据,所以每次仪器开机时都要去查看数据库中最后一条历史记录的文件号,然后以此文件号为基础向数据库中添加历史记录(文件号唯一代表每条历史记录,不能重复)。下面是我获取文件号的代码:
QSqlQuery history_query;
history_query.exec("SELECT * FROM history");
if(!history_query.next())
{
g_iFileNum = 0;
}
else
{
history_query.last();
g_iFileNum = history_query.record().value("FileNumber").toInt() + 1;
}
错误点就在于last()函数的使用,last()函数会将数据库中所有的记录都放到了history_query的缓冲区中,如果数据库中history表数据量庞大的话就会造成内存急剧攀升,此段代码在主界面的构造函数之中,以后随着历史记录的增多,开机内存会越来越大,以致出现上述故障。
注意:下面这种获取最后一条历史记录的方式同样会造成上述故障。
QSqlTableModel *model; //用于显示历史记录
model = new QSqlTableModel(this);
model->setTable("history");
model->setEditStrategy(QSqlTableModel::OnFieldChange);
model->select();
while (model->canFetchMore())
{
// model->clear(); //使用clear不能达到预期效果,即无效
model->fetchMore();
}
int row_num = model->rowCount();
g_iFileNum = model->record(row_num - 1).value("FileNumber").toInt() + 1;
3.解决方案:
我的解决方案就是使用排序来获取最后一条历史数据,实验表明此种方式将避免上述出现的问题,效果良好,代码如下:
//
// 历史记录部分的处理
//
QSqlTableModel *model; //用于显示历史记录
model = new QSqlTableModel(this);
model->setTable("history");
model->setEditStrategy(QSqlTableModel::OnFieldChange);
/* 获取文件号(取文件号最好不要用last函数或者fetchMore函数,数据库大时会造成系统崩溃) */
model->setSort(0,Qt::DescendingOrder); //降序排列
model->select();
model->query().first(); //必须使用,因为排序后当前行不是第一行,而是第255行
g_iFileNum = model->query().record().value("FileNumber").toInt() + 1;
/* 获取文件号后将数据库恢复为升序排列 */
model->setSort(0,Qt::AscendingOrder); //升序排列
model->select();