Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-2299

REG->6.5: Memory/Reference Leak with connecting signals to lambda functions referencing "self"

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P2: Important
    • 6.5.2, 6.5.1, 6.6.0
    • 6.5.0
    • PySide
    • None
    • 5b39b316e (dev), 58ec2ac3d (6.5), f26d22209 (dev), 683c8ed5d (6.5), cc2054bc1 (6.5.1), e31b4220f (tqtc/6.5.1), b81f2c3f9 (dev), e2a3d76b9 (6.5), 0bf8ce702 (dev), f21ed0581 (6.5), 80da3a11d (6.5.1), 9a7dfdd57 (tqtc/6.5.1), f0109334c (dev), 7222d8a04 (6.5)

    Description

      Hello Qt for Python team,

       

      PyQtGraph maintainer here, we have an issue with extra reference counts (and by extension a memory leak) to signal/slot mechanisms where a signal is connected to a lambda function that references self.

      Here is a non-pyqtgraph version to replicate the issue, the psutil library is needed to track memory usage:

      from PySide6 import QtCore, QtWidgets
      import psutil
      
      class Leaker:
          def __init__(self):
              parent = None
              parent = QtWidgets.QWidget()    # this line seemingly makes PySide < 6.5.0 not leak
              wgt= QtWidgets.QSpinBox(parent)
              wgt.valueChanged.connect(self.mkChangeCallback(wgt))
      
          def mkChangeCallback(self, w):
              return lambda *args: self.widgetChanged(w, *args)
              
          def widgetChanged(self, w, *args):
              pass
      
      app = QtWidgets.QApplication([])
      timer = QtCore.QTimer()
      proc = psutil.Process()
      
      rss0 = proc.memory_info().rss
      
      cnt = 0
      def timer_cb():
          global cnt
          rss = proc.memory_info().rss
          print(f'{cnt}: {(rss - rss0)/1048576:.1f} MB')
          Leaker()
          cnt += 1
          if cnt > 500:
              timer.stop()
              app.exit()
      
      timer.timeout.connect(timer_cb)
      timer.start(0)
      app.exec() if hasattr(app, 'exec') else app.exec_()
      

      I'm going to mark as affecting 6.5.0 but I'm fairly certain we've seen this issue in much older versions of pyside

      Here is the issue in our bug-tracker: https://github.com/pyqtgraph/pyqtgraph/issues/2672
       

      Attachments

        1. pyside2299_diag.diff
          2 kB
        2. pyside2299_log.txt
          2 kB
        3. pyside2299_minimal.py
          0.5 kB
        4. pyside2299.py
          0.8 kB

        Issue Links

          For Gerrit Dashboard: PYSIDE-2299
          # Subject Branch Project Status CR V

          Activity

            People

              kleint Friedemann Kleint
              j9ac9k Ognyan Moore
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: