使用临时数据表修复内存泄漏(堆与堆栈)

Fixing memory leak with temporary data table (heap vs stack)

本文关键字:泄漏 堆栈 内存 数据表      更新时间:2023-10-16

我有一段用于填充表的代码。它会在磁盘上打开一个文件并将数据扔到表中。

if (file.open(QIODevice::ReadOnly))
    {
      QDataStream stream(&file);
      qint32 numRows, numColumns;
      stream >> numRows >> numColumns;
      QStandardItemModel* tempModel = new QStandardItemModel;
      tempModel->setRowCount(numRows);
      tempModel->setColumnCount(numColumns);
      for (int i = 0; i < numRows ; ++i) {
        for (int j = 0; j < numColumns; j++) {
          QStandardItem* tempItem = new QStandardItem; // stored in heap
          tempItem->read(stream);
          tempModel->setItem(i, j, tempItem);
        }
      }
      file.close();
      tableView->setModel(tempModel);
      ...
    }

此代码有效。但是我遇到的问题是,我打开的文件越多,使用的内存就越多,而且永远不会出现故障。例如,如果我添加第二个文件,则不再需要存储前一个文件的模型。我想删除它。

我猜内存没有被释放,因为它永远不会被删除,因为我使用的是 new 关键字和指针。

如果我们以tempItem for循环为例,我想我必须做一些类似的事情来修复它:

      for (int i = 0; i < numRows ; ++i) {
        for (int j = 0; j < numColumns; j++) {
          //QStandardItem* tempItem = new QStandardItem;
          QStandardItem tempItem; // store on stack and delete at end of scope
          //tempItem->read(stream);
          tempItem.read(stream);
          tempModel->setItem(i, j, tempItem);
        }

但即便如此,它也会抛出一个错误,因为QStandardItemModelsetItem(见这里)需要一个QStandardItem指针。

如果可能的话,我想为tempModeltempItem解决这个问题。我在这里做错了什么?

内存泄漏不是由于QStandardItem所有权造成的。setItem() 方法获取QStandardItem对象的所有权,当释放QStandardItemModel对象时,将自动释放这些对象。

内存泄漏是由于 tableView->setModel(tempModel); 语句造成的,因为该方法具有所有权。更改模型或释放视图时,您负责释放模型。

有关详细信息,请参阅此文档。

例如:

QItemSelectionModel *m = tableView->selectionModel();
tableView->setModel(tempModel);
delete m;

我最终在我的头文件和主窗口的初始化列表中设置了一个QStandardItemModel

MyApp.h

...
  QStandardItemModel* mainModel;
...

米亚普.cpp

...
MyApp::MyApp(QWidget* parent)
  : QMainWindow(parent),
    mainModel(new QStandardItemModel(tableView)),
...

我更改了应用程序的工作方式,以便我的表视图只需要一个模型。每当我需要添加新数据集来填充表时,我都会完全清除当前表,创建一个新的临时模型,然后将临时模型设置为主模型。

mainTableModel->clear();
QStandardItemModel* tempModel = new QStandardItemModel;
tempModel->setRowCount(numRows);
tempModel->setColumnCount(numColumns);
for (int i = 0; i < numRows ; ++i) {
  for (int j = 0; j < numColumns; j++) {
    QStandardItem* tempItem = new QStandardItem();
    tempItem->read(stream);
    tempModel->setItem(i, j, tempItem);
  }
}
file.close();    
mainModel = tempModel;    
tableView->setModel(mainModel);

清除模型并重用它可以减少内存泄漏,但不能修复内存泄漏。