Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Right way to delete resources
Forum Updated to NodeBB v4.3 + New Features

Right way to delete resources

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 3 Posters 2.0k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Mark81
    wrote on last edited by Mark81
    #1

    I'm not sure if I'm doing it correcly.
    In a QMainWindow application I create and populate tabs for a QWidgetTab at runtime. Then I need to free the resources to create a new set.

    Here how I create them:

    void MainWindow::createTabs()
    {
         QStringList names; // contains the list of the tab's name
        foreach (QString name, names)
        {
            QWidget *widget = new QWidget();
            QScrollArea *scrollArea = new QScrollArea();
            scrollArea->setWidget(widget);
            loadTab(view, widget, name);
            ui->tabView->addTab(scrollArea, name);
        }
    }
    
    void MainWindow::loadTab(MainWindow::Views view, QWidget *widget, QString tab)
    {
        FlowLayout *layout = new FlowLayout();
        layout->setOrientation(Qt::Vertical);
        widget->setLayout(layout);
        populateTab(view, tab, widget);
    }
    
    void MainWindow::populateTab(MainWindow::Views view, QString tab, QWidget *parent)
    {    
        QMutableMapIterator<int, DatabaseManager::Data> i(_mapData[tab]); // contains the information to display controls
        while (i.hasNext())
        {
            i.next();
            DatabaseManager::Data data = i.value();
    
            QGroupBox *group = retrieveGroup(data.group, tab, parent);
            QFormLayout *formLayout = qobject_cast<QFormLayout *>(group->layout());
    
            QLineEdit *widget = new QLineEdit();
            data.widget = widget;
            i.setValue(data);
            QLabel *label = new QLabel(data.description);
            formLayout->addRow(label, data.widget);
        }
    }
    
    QGroupBox *MainWindow::retrieveGroup(QString name, QString tab, QWidget *parent)
    {
        if (_mapGroups[tab].contains(name)) return _mapGroups[tab][name];
    
        QGroupBox *group = new QGroupBox(name, parent);
    
        QFormLayout *formLayout = new QFormLayout();
        group->setLayout(formLayout);
        parent->layout()->addWidget(group);
        _mapGroups[tab][name] = group;
        return group;
    }
    

    And here how I'm trying to free resources:

    for (int i = 0; i < ui->tabView->count(); i++)
    {
        qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
        delete ui->tabView->widget(0);
    }
    ui->tabView->clear();
    _mapGroups.clear();
    

    But I see a memory leakage: every time I load the very same set of tabs the memory occupation of my process increases.
    I tried to change this:

        qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
    

    to

        qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindChildrenRecursively));
    

    but I got a crash in Qt code.
    How would you delete all the newly crated objects?

    J 1 Reply Last reply
    0
    • M Mark81

      I'm not sure if I'm doing it correcly.
      In a QMainWindow application I create and populate tabs for a QWidgetTab at runtime. Then I need to free the resources to create a new set.

      Here how I create them:

      void MainWindow::createTabs()
      {
           QStringList names; // contains the list of the tab's name
          foreach (QString name, names)
          {
              QWidget *widget = new QWidget();
              QScrollArea *scrollArea = new QScrollArea();
              scrollArea->setWidget(widget);
              loadTab(view, widget, name);
              ui->tabView->addTab(scrollArea, name);
          }
      }
      
      void MainWindow::loadTab(MainWindow::Views view, QWidget *widget, QString tab)
      {
          FlowLayout *layout = new FlowLayout();
          layout->setOrientation(Qt::Vertical);
          widget->setLayout(layout);
          populateTab(view, tab, widget);
      }
      
      void MainWindow::populateTab(MainWindow::Views view, QString tab, QWidget *parent)
      {    
          QMutableMapIterator<int, DatabaseManager::Data> i(_mapData[tab]); // contains the information to display controls
          while (i.hasNext())
          {
              i.next();
              DatabaseManager::Data data = i.value();
      
              QGroupBox *group = retrieveGroup(data.group, tab, parent);
              QFormLayout *formLayout = qobject_cast<QFormLayout *>(group->layout());
      
              QLineEdit *widget = new QLineEdit();
              data.widget = widget;
              i.setValue(data);
              QLabel *label = new QLabel(data.description);
              formLayout->addRow(label, data.widget);
          }
      }
      
      QGroupBox *MainWindow::retrieveGroup(QString name, QString tab, QWidget *parent)
      {
          if (_mapGroups[tab].contains(name)) return _mapGroups[tab][name];
      
          QGroupBox *group = new QGroupBox(name, parent);
      
          QFormLayout *formLayout = new QFormLayout();
          group->setLayout(formLayout);
          parent->layout()->addWidget(group);
          _mapGroups[tab][name] = group;
          return group;
      }
      

      And here how I'm trying to free resources:

      for (int i = 0; i < ui->tabView->count(); i++)
      {
          qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
          delete ui->tabView->widget(0);
      }
      ui->tabView->clear();
      _mapGroups.clear();
      

      But I see a memory leakage: every time I load the very same set of tabs the memory occupation of my process increases.
      I tried to change this:

          qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
      

      to

          qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindChildrenRecursively));
      

      but I got a crash in Qt code.
      How would you delete all the newly crated objects?

      J Offline
      J Offline
      JahJerMar
      wrote on last edited by JahJerMar
      #2

      @Mark81
      I believe you have two problems here....

      1. When you parent a widget like a tab to a TabWidget, when the tabwidget goes out of scope, it's destructor is called. If you're trying to delete
        the tab from the tabwidget, it would be a double delete because when setlayout is called, it automatically makes the children tabs parented to the tabwidget which autmatically
        "deletes" its children when it goes out of scope.
      2. That kind of leads into 2... that means if that tabwidget exists for the lifetime of the program, you will see your "memory go up." even though you removed the widget etc.
        To free memory in the middle of the program I think you would need to unparent the child widget... then keep a pointer to the address then call delete.

      I may be wrong because I am a newbie so take what I say with a grain of salt.

      Also, a quick answer from a google search explains point 2 a bit further.

      "It is not necessary that your operating system memory manager will release each and every deallocated heap memory byte. Usually it does not. But that doesn't mean that the memory has leaked.

      For example, you may begin with 5 mb of memory usage, then allocate another 5 mb worth of objects, and when deallocated it only frees 3 mb and you are left with 7 mb usage. But if you allocate the 5 mb worth of objects again, memory usage will not jump to 12 mb, it will still jump to 10, because those 2 unreleased mb will be reused.

      Take a look here, where I investigated one such issue. As you can see, for a while the memory usage keeps growing, from 41 to 53 mb, but then it stabilizes and it doesn't grow further even after hundreds of allocations/deallocations. Different OS memory managers work in a different way, the amount total memory and free memory are also a factor, possibly the application's own usage patterns as well.

      It can be regarded as a leak only if each time you do that the memory usage increases by 2 mb and never reaches a stable level. If you make a custom widget with a debug message in the destructor, you can verify when and whether it and its children are being destroyed. But again, there is no guarantee that you reclaim 100% of the used memory."

      M 1 Reply Last reply
      2
      • J JahJerMar

        @Mark81
        I believe you have two problems here....

        1. When you parent a widget like a tab to a TabWidget, when the tabwidget goes out of scope, it's destructor is called. If you're trying to delete
          the tab from the tabwidget, it would be a double delete because when setlayout is called, it automatically makes the children tabs parented to the tabwidget which autmatically
          "deletes" its children when it goes out of scope.
        2. That kind of leads into 2... that means if that tabwidget exists for the lifetime of the program, you will see your "memory go up." even though you removed the widget etc.
          To free memory in the middle of the program I think you would need to unparent the child widget... then keep a pointer to the address then call delete.

        I may be wrong because I am a newbie so take what I say with a grain of salt.

        Also, a quick answer from a google search explains point 2 a bit further.

        "It is not necessary that your operating system memory manager will release each and every deallocated heap memory byte. Usually it does not. But that doesn't mean that the memory has leaked.

        For example, you may begin with 5 mb of memory usage, then allocate another 5 mb worth of objects, and when deallocated it only frees 3 mb and you are left with 7 mb usage. But if you allocate the 5 mb worth of objects again, memory usage will not jump to 12 mb, it will still jump to 10, because those 2 unreleased mb will be reused.

        Take a look here, where I investigated one such issue. As you can see, for a while the memory usage keeps growing, from 41 to 53 mb, but then it stabilizes and it doesn't grow further even after hundreds of allocations/deallocations. Different OS memory managers work in a different way, the amount total memory and free memory are also a factor, possibly the application's own usage patterns as well.

        It can be regarded as a leak only if each time you do that the memory usage increases by 2 mb and never reaches a stable level. If you make a custom widget with a debug message in the destructor, you can verify when and whether it and its children are being destroyed. But again, there is no guarantee that you reclaim 100% of the used memory."

        M Offline
        M Offline
        Mark81
        wrote on last edited by
        #3

        @JahJerMar Thanks a lot for your answer.
        Some more details:

        • I do have a memory leak: every time I allocate the same set of tabs the memory usage increase of about 2.1 MB and going on with free resources and allocate again it reaches hundreds of MB.

        • About QTabWidget: I'm not sure to understand. I know that when I remove a tab it does not delete the content, this is why I call qDeleteAll and then delete the widget. But do this two commands ensure that all the children objects are deleted as well?

        • When my tabs were populated with simpler widgets (i.e. just a QWidget, a QVBoxLayout and plenty of QLabels) the code above worked and the memory usage didn't grow.

        I'm afraid about all the nested objects I create:

        • many QScrollArea() as tabs
        • a QWidget() as area's tab
        • a FlowLayout() as widget's layout
        • many QGroupBox(widget) in the layout
        • a QFormLayout() as group's layout
        • many QLineEdit () in the layout

        My code pretends to delete all the above items, cycling among each tab and deleting the "direct children" and the tab itself (the QScrollArea object). I've already tried to add a debug line in the destructor of FlowLayout: it is actually called, though less times as I expect (i.e. I have 16 tabs, hence 16 FlowLayout but I get only 8 debug messages).

        Because all of them are inside layouts and the layouts are assigned to widgets, deleting the widgets does not delete also their layouts and the contained objects?

        1 Reply Last reply
        0
        • M Offline
          M Offline
          Mark81
          wrote on last edited by
          #4

          Something you. I was confused by my code revision and I forgot a line in the code:

          QLineEdit *widget = new QLineEdit();
          data.widget = widget;
          i.setValue(data);
          

          this save the pointer to the newly created widget into my Data struct.
          Actually, after deleting the resources those pointers are still valid! I mean they still points to the widgets - I bet here is the problem.
          But adding this before the code already posted above:

          QMapIterator<QString, QMap<int, DatabaseManager::Data>> i1(_mapData);
          while (i1.hasNext())
          {
              i1.next();
              QMapIterator<int, DatabaseManager::Data> i2(i1.value());
              while (i2.hasNext())
              {
                  i2.next();
                  delete i2.value().widget; // this is the pointer to the created widgets!
              }
          }
          

          leads to a segmentation fault on the delete call.

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Mark81
            wrote on last edited by Mark81
            #5

            With this code the memory usage increases now of 40-50 kB each time (instead of 2.1 MB):

            QMutableMapIterator<QString, QMap<int, DatabaseManager::Data>> i1(_mapData);
            while (i1.hasNext())
            {
                i1.next();
                QMutableMapIterator<int, DatabaseManager::Data> i2(i1.value());
                while (i2.hasNext())
                {
                    i2.next();
                    if (i2.value().widget)
                    {
                        DatabaseManager::Data data = i2.value();
                        data.widget->deleteLater();
                        data.widget = nullptr;
                        i2.setValue(data);
                    }
                }
            }
            
            QMutableMapIterator<QString, QMap<QString, QGroupBox *>> i3(_mapGroups);
            while (i3.hasNext())
            {
                i3.next();
                QMutableMapIterator<QString, QGroupBox *> i4(i3.value());
                while (i4.hasNext())
                {
                    i4.next();
                    qDeleteAll(i4.value()->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                    i4.value()->deleteLater();
                }
            }
            
            for (int i = 0; i < ui->tabView->count(); i++)
            {
                QScrollArea *a = qobject_cast<QScrollArea *>(ui->tabView->widget(0));
                qDeleteAll(a->widget()->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                delete ui->tabView->widget(0);
            }
            ui->tabView->clear();
            
            jsulmJ 1 Reply Last reply
            0
            • M Mark81

              With this code the memory usage increases now of 40-50 kB each time (instead of 2.1 MB):

              QMutableMapIterator<QString, QMap<int, DatabaseManager::Data>> i1(_mapData);
              while (i1.hasNext())
              {
                  i1.next();
                  QMutableMapIterator<int, DatabaseManager::Data> i2(i1.value());
                  while (i2.hasNext())
                  {
                      i2.next();
                      if (i2.value().widget)
                      {
                          DatabaseManager::Data data = i2.value();
                          data.widget->deleteLater();
                          data.widget = nullptr;
                          i2.setValue(data);
                      }
                  }
              }
              
              QMutableMapIterator<QString, QMap<QString, QGroupBox *>> i3(_mapGroups);
              while (i3.hasNext())
              {
                  i3.next();
                  QMutableMapIterator<QString, QGroupBox *> i4(i3.value());
                  while (i4.hasNext())
                  {
                      i4.next();
                      qDeleteAll(i4.value()->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                      i4.value()->deleteLater();
                  }
              }
              
              for (int i = 0; i < ui->tabView->count(); i++)
              {
                  QScrollArea *a = qobject_cast<QScrollArea *>(ui->tabView->widget(0));
                  qDeleteAll(a->widget()->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                  qDeleteAll(ui->tabView->widget(0)->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly));
                  delete ui->tabView->widget(0);
              }
              ui->tabView->clear();
              
              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @Mark81 said in Right way to delete resources:

              i4.value()->findChildren<QWidget *>("", Qt::FindDirectChildrenOnly)

              Are you sure this actually finds anything?

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved