Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Memory leak after closing window
Forum Updated to NodeBB v4.3 + New Features

Memory leak after closing window

Scheduled Pinned Locked Moved Solved Qt for Python
5 Posts 3 Posters 1.0k Views
  • 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.
  • feiyuhuahuoF Offline
    feiyuhuahuoF Offline
    feiyuhuahuo
    wrote on last edited by feiyuhuahuo
    #1
    from PySide6.QtWidgets import QVBoxLayout, QPushButton, QWidget
    from PySide6.QtUiTools import QUiLoader
    from PySide6.QtWidgets import QApplication, QLabel, QMainWindow
    from PySide6.QtCore import Qt, QPoint, QPointF, QRect, QObject
    from PySide6.QtGui import QPixmap, QPainter
    
    class BaseImgFrame(QLabel):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.painter = QPainter()
            self.resize(512, 512)
            self.img, self.scaled_img = None, None
            self.img_tl = QPointF(0., 0.)  # 图片左上角在控件坐标系的坐标
            self.interpolation = Qt.FastTransformation
    
        def closeEvent(self, event):
            self.deleteLater()
            event.accept()
    
        def paintEvent(self, e):
            self.painter.begin(self)
            self.painter.drawPixmap(self.img_tl, self.scaled_img)
            self.painter.end()
    
        def paint_img(self, img_path_or_pix_map):
            self.img = QPixmap(img_path_or_pix_map)
            self.scaled_img = self.img.scaled(self.size(), Qt.KeepAspectRatio, self.interpolation)
            self.update()
    
    
    class BaseImgWindow(QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            loader = QUiLoader()
            loader.registerCustomWidget(BaseImgFrame)
            self.ui = loader.load('ui_files/base_img_window.ui')
            self.setCentralWidget(self.ui)
            self.resize(512, 512)
    
        def closeEvent(self, event):
            self.deleteLater()
            event.accept()
    
        def paint_img(self, img_path_or_pix_map):
            self.ui.img_area.paint_img(img_path_or_pix_map)
    
    
    class ImageDisplay(QMainWindow):
        def __init__(self):
            super().__init__()
            self.central_widget = QWidget(self)
            self.setCentralWidget(self.central_widget)
            lay = QVBoxLayout(self.central_widget)
            self.button = QPushButton(self)
            lay.addWidget(self.button)
            self.central_widget.setLayout(lay)
            self.button.clicked.connect(self.add)
    
        def add(self):
            window_new_img = BaseImgWindow(self)
            window_new_img.setAttribute(Qt.WA_DeleteOnClose)
            window_new_img.paint_img(QPixmap('D:\Data\yyyy\原图/8.10.jpg'))
            window_new_img.show()
    
    
    if __name__ == '__main__':
        app = QApplication()
        window = ImageDisplay()
        window.show()
        app.exec()
    

    Click the button, a new window will show. But the memory does not release correctly after closing the window (Better test with a large image). The ui file is here: https://github.com/feiyuhuahuo/HuaHuoLabel/blob/new_fw/ui_files/base_img_window.ui
    The PySide6 version is 6.5.2 and OS is Windows11.

    jsulmJ JoeCFDJ 2 Replies Last reply
    0
    • feiyuhuahuoF feiyuhuahuo
      from PySide6.QtWidgets import QVBoxLayout, QPushButton, QWidget
      from PySide6.QtUiTools import QUiLoader
      from PySide6.QtWidgets import QApplication, QLabel, QMainWindow
      from PySide6.QtCore import Qt, QPoint, QPointF, QRect, QObject
      from PySide6.QtGui import QPixmap, QPainter
      
      class BaseImgFrame(QLabel):
          def __init__(self, parent=None):
              super().__init__(parent)
              self.painter = QPainter()
              self.resize(512, 512)
              self.img, self.scaled_img = None, None
              self.img_tl = QPointF(0., 0.)  # 图片左上角在控件坐标系的坐标
              self.interpolation = Qt.FastTransformation
      
          def closeEvent(self, event):
              self.deleteLater()
              event.accept()
      
          def paintEvent(self, e):
              self.painter.begin(self)
              self.painter.drawPixmap(self.img_tl, self.scaled_img)
              self.painter.end()
      
          def paint_img(self, img_path_or_pix_map):
              self.img = QPixmap(img_path_or_pix_map)
              self.scaled_img = self.img.scaled(self.size(), Qt.KeepAspectRatio, self.interpolation)
              self.update()
      
      
      class BaseImgWindow(QMainWindow):
          def __init__(self, parent=None):
              super().__init__(parent)
              loader = QUiLoader()
              loader.registerCustomWidget(BaseImgFrame)
              self.ui = loader.load('ui_files/base_img_window.ui')
              self.setCentralWidget(self.ui)
              self.resize(512, 512)
      
          def closeEvent(self, event):
              self.deleteLater()
              event.accept()
      
          def paint_img(self, img_path_or_pix_map):
              self.ui.img_area.paint_img(img_path_or_pix_map)
      
      
      class ImageDisplay(QMainWindow):
          def __init__(self):
              super().__init__()
              self.central_widget = QWidget(self)
              self.setCentralWidget(self.central_widget)
              lay = QVBoxLayout(self.central_widget)
              self.button = QPushButton(self)
              lay.addWidget(self.button)
              self.central_widget.setLayout(lay)
              self.button.clicked.connect(self.add)
      
          def add(self):
              window_new_img = BaseImgWindow(self)
              window_new_img.setAttribute(Qt.WA_DeleteOnClose)
              window_new_img.paint_img(QPixmap('D:\Data\yyyy\原图/8.10.jpg'))
              window_new_img.show()
      
      
      if __name__ == '__main__':
          app = QApplication()
          window = ImageDisplay()
          window.show()
          app.exec()
      

      Click the button, a new window will show. But the memory does not release correctly after closing the window (Better test with a large image). The ui file is here: https://github.com/feiyuhuahuo/HuaHuoLabel/blob/new_fw/ui_files/base_img_window.ui
      The PySide6 version is 6.5.2 and OS is Windows11.

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @feiyuhuahuo It is up to the OS when the memory is really released. Closing a window does not necessary mean that its memory is immediately released. If you really want to find out whether there is a memory leak you should open and close that window many times and look at the memory consumption.

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

      1 Reply Last reply
      1
      • feiyuhuahuoF feiyuhuahuo
        from PySide6.QtWidgets import QVBoxLayout, QPushButton, QWidget
        from PySide6.QtUiTools import QUiLoader
        from PySide6.QtWidgets import QApplication, QLabel, QMainWindow
        from PySide6.QtCore import Qt, QPoint, QPointF, QRect, QObject
        from PySide6.QtGui import QPixmap, QPainter
        
        class BaseImgFrame(QLabel):
            def __init__(self, parent=None):
                super().__init__(parent)
                self.painter = QPainter()
                self.resize(512, 512)
                self.img, self.scaled_img = None, None
                self.img_tl = QPointF(0., 0.)  # 图片左上角在控件坐标系的坐标
                self.interpolation = Qt.FastTransformation
        
            def closeEvent(self, event):
                self.deleteLater()
                event.accept()
        
            def paintEvent(self, e):
                self.painter.begin(self)
                self.painter.drawPixmap(self.img_tl, self.scaled_img)
                self.painter.end()
        
            def paint_img(self, img_path_or_pix_map):
                self.img = QPixmap(img_path_or_pix_map)
                self.scaled_img = self.img.scaled(self.size(), Qt.KeepAspectRatio, self.interpolation)
                self.update()
        
        
        class BaseImgWindow(QMainWindow):
            def __init__(self, parent=None):
                super().__init__(parent)
                loader = QUiLoader()
                loader.registerCustomWidget(BaseImgFrame)
                self.ui = loader.load('ui_files/base_img_window.ui')
                self.setCentralWidget(self.ui)
                self.resize(512, 512)
        
            def closeEvent(self, event):
                self.deleteLater()
                event.accept()
        
            def paint_img(self, img_path_or_pix_map):
                self.ui.img_area.paint_img(img_path_or_pix_map)
        
        
        class ImageDisplay(QMainWindow):
            def __init__(self):
                super().__init__()
                self.central_widget = QWidget(self)
                self.setCentralWidget(self.central_widget)
                lay = QVBoxLayout(self.central_widget)
                self.button = QPushButton(self)
                lay.addWidget(self.button)
                self.central_widget.setLayout(lay)
                self.button.clicked.connect(self.add)
        
            def add(self):
                window_new_img = BaseImgWindow(self)
                window_new_img.setAttribute(Qt.WA_DeleteOnClose)
                window_new_img.paint_img(QPixmap('D:\Data\yyyy\原图/8.10.jpg'))
                window_new_img.show()
        
        
        if __name__ == '__main__':
            app = QApplication()
            window = ImageDisplay()
            window.show()
            app.exec()
        

        Click the button, a new window will show. But the memory does not release correctly after closing the window (Better test with a large image). The ui file is here: https://github.com/feiyuhuahuo/HuaHuoLabel/blob/new_fw/ui_files/base_img_window.ui
        The PySide6 version is 6.5.2 and OS is Windows11.

        JoeCFDJ Offline
        JoeCFDJ Offline
        JoeCFD
        wrote on last edited by JoeCFD
        #3

        @feiyuhuahuo @jsulm is right. You can make a loop to create and destroy the window a few times and check if the memory leak problem stays. Never used python. Do you need to clear self.img after it is scaled to self.scaled_img?

        1 Reply Last reply
        0
        • feiyuhuahuoF Offline
          feiyuhuahuoF Offline
          feiyuhuahuo
          wrote on last edited by feiyuhuahuo
          #4

          @jsulm Hi, I hope that the memory can be released after the window is closed. So I add such code: window_new_img.setAttribute(Qt.WA_DeleteOnClose). But it doesn't. I test with a large image, and ~75M memory is occupied every time I show a new window. Only ~2M memory is released every time I close a window. I find it's about registerCustomWidget. If I replace class BaseImgWindow with code:

          class BaseImgWindow(QMainWindow):
              def __init__(self, parent=None):
                  super().__init__(parent)
                  self.ui = QMainWindow(self)
                  layout = QVBoxLayout(self.ui)
                  self.ui.setLayout(layout)
          
                  self.label = BaseImgFrame(self)
                  layout.addWidget(self.label)
          
                  self.setCentralWidget(self.ui)
                  self.resize(512, 512)
          
              def closeEvent(self, event):
                  self.deleteLater()
                  event.accept()
          
              def paint_img(self, img_path_or_pix_map):
                  self.label.paint_img(img_path_or_pix_map)
          

          Then the memory can be correctly released. Confused why there's such a difference.
          @JoeCFD I add code del self.img and del self.scaled_img in closeEvent. But that just doesn't work.

          1 Reply Last reply
          0
          • feiyuhuahuoF Offline
            feiyuhuahuoF Offline
            feiyuhuahuo
            wrote on last edited by
            #5

            @feiyuhuahuo said in Memory leak after closing window:

            The PySide6 version is 6.5.2 and OS is Windows11.

            Hi @jsulm @JoeCFD , seems I have to use pyside6-uic to convert my ui file to python code to avoid this problem. But still, I found another memory bug: https://forum.qt.io/topic/152101/memory-can-not-release-correctly-because-of-using-lambda-as-slot
            Thanks a lot for the help.

            1 Reply Last reply
            0
            • feiyuhuahuoF feiyuhuahuo has marked this topic as solved on

            • Login

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