Потребление памяти Python QTableView (PySide1,2 и PyQt4,5) - PullRequest
0 голосов
/ 15 января 2019

Я написал приложение для хранения данных MySQL в QTableView. Для упрощения приложения я написал генератор случайных данных. Если вы инициируете таблицу со случайными данными, как в примере кода, потребление памяти возрастет примерно на 400 МБ. После опции сброса для QTableView вы никогда не достигнете значения выделенной памяти с самого начала приложения. Это только увеличивается. Значение левой выделенной памяти зависит от метода сброса QTableView.

Если вы хотите сбросить таблицу, у вас есть разные опции, посмотрите на строку 98. После каждой попытки (нажмите кнопку: initTableData и нажмите кнопку: сброс) вы можете наблюдать различное значение левой выделенной памяти. Вы также можете попробовать различные оболочки Qt, такие как PyQt4,5 или PySide 1,2, посмотрите на строку 1-13. Я просто хочу знать, что я делаю что-то не так, прежде чем открыть отчет об ошибке. Я протестировал приложение с linux mint 18.2 и нестабильным Debian.

Заранее спасибо,

Phil

Valgrind checks: I did three rounds in a row of initTableData and reset

(option 0:) valgrind --leak-check=full python main.py 

==10677== LEAK SUMMARY:
==10677==    definitely lost: 613,864 bytes in 75,920 blocks
==10677==    indirectly lost: 41,482,207 bytes in 86,140 blocks
==10677==      possibly lost: 1,227,682 bytes in 4,114 blocks
==10677==    still reachable: 5,249,822 bytes in 37,463 blocks
==10677==                       of which reachable via heuristic:
==10677==                         length64           : 3,272 bytes in 59 blocks
==10677==                         newarray           : 2,048 bytes in 48 blocks
==10677==                         multipleinheritance: 40 bytes in 1 blocks
==10677==         suppressed: 0 bytes in 0 blocks
==10677== Reachable blocks (those to which a pointer was found) are not shown.


(option 1:) valgrind --leak-check=full python main.py 

==13445== LEAK SUMMARY:
==13445==    definitely lost: 622,896 bytes in 77,049 blocks
==13445==    indirectly lost: 41,474,207 bytes in 85,014 blocks
==13445==      possibly lost: 1,227,690 bytes in 4,115 blocks
==13445==    still reachable: 13,637,676 bytes in 37,476 blocks
==13445==                       of which reachable via heuristic:
==13445==                         length64           : 3,272 bytes in 59 blocks
==13445==                         newarray           : 2,048 bytes in 48 blocks
==13445==                         multipleinheritance: 1,744 bytes in 3 blocks
==13445==         suppressed: 0 bytes in 0 blocks



(option 2:) valgrind --leak-check=full python main.py 

==11887== LEAK SUMMARY:
==11887==    definitely lost: 870,736 bytes in 108,029 blocks
==11887==    indirectly lost: 55,284,839 bytes in 108,075 blocks
==11887==      possibly lost: 1,210,242 bytes in 4,076 blocks
==11887==    still reachable: 705,918,604 bytes in 14,726,014 blocks
==11887==                       of which reachable via heuristic:
==11887==                         length64           : 3,272 bytes in 59 blocks
==11887==                         newarray           : 2,048 bytes in 48 blocks
==11887==                         multipleinheritance: 3,280 bytes in 4 blocks
==11887==         suppressed: 0 bytes in 0 blocks

пример кода:

#from PySide.QtGui      import *
#from PySide.QtCore     import *

#from PySide2.QtGui     import *
#from PySide2.QtCore    import *
#from PySide2.QtWidgets import *

#from PyQt4.QtGui       import *
#from PyQt4.QtCore      import *

from PyQt5.QtGui       import *
from PyQt5.QtCore      import *
from PyQt5.QtWidgets   import *

class Ui_Table(object):
    def setupUi(self, Table):
        Table.setObjectName("Table")
        Table.resize(824, 488)
        self.verticalLayout = QVBoxLayout(Table)
        self.verticalLayout.setObjectName("verticalLayout")
        self.frame = QFrame(Table)
        self.frame.setFrameShape(QFrame.StyledPanel)
        self.frame.setFrameShadow(QFrame.Raised)
        self.frame.setObjectName("frame")
        self.horizontalLayout = QHBoxLayout(self.frame)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.btnInitTableData = QPushButton(self.frame)
        self.btnInitTableData.setObjectName("btnInitTableData")
        self.horizontalLayout.addWidget(self.btnInitTableData)
        self.btnReset = QPushButton(self.frame)
        self.btnReset.setObjectName("btnReset")
        self.horizontalLayout.addWidget(self.btnReset)
        spacerItem = QSpacerItem(601, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.verticalLayout.addWidget(self.frame)
        self.tableView = QTableView(Table)
        self.tableView.setObjectName("tableView")
        self.verticalLayout.addWidget(self.tableView)
        self.retranslateUi(Table)
        QMetaObject.connectSlotsByName(Table)


    def retranslateUi(self, Table):
        _translate = QCoreApplication.translate
        Table.setWindowTitle(_translate("Table", "Table"))
        self.btnInitTableData.setText(_translate("Table", "init TableData"))
        self.btnReset.setText(_translate("Table", "reset"))



class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.stackedWidget = QStackedWidget(self.centralwidget)
        self.stackedWidget.setObjectName("stackedWidget")
        self.gridLayout.addWidget(self.stackedWidget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setGeometry(QRect(0, 0, 800, 30))
        self.menubar.setObjectName("menubar")
        self.menuFile = QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionEnd = QAction(MainWindow)
        self.actionEnd.setObjectName("actionEnd")
        self.menuFile.addAction(self.actionEnd)
        self.menubar.addAction(self.menuFile.menuAction())
        self.retranslateUi(MainWindow)
        self.actionEnd.triggered.connect(MainWindow.close)
        QMetaObject.connectSlotsByName(MainWindow)


    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionEnd.setText(_translate("MainWindow", "End"))



class Table(Ui_Table):   
    def initTableData(self):
        for row in range(0, 27000):
            lst = []
            for idx in range(0, 34):    # init array with number columns
                lst.append(QStandardItem(str(idx)))

            self.tableView.model().appendRow(lst)


    def reset(self):
        #option 0:
        #self.tableView.model().clear()                              # memory consumption around 15MB each reset

        #option 1:
        #self.tableView.model().setRowCount(0)                       # memory consumption around 15MB each reset

        #option 2:
        #self.tableView.setModel(QStandardItemModel(self.tableView)) # memory consumption around 400MB each reset
        pass


    def __init__(self, main):
        self.main = main
        self.widget = QWidget()
        self.setupUi(self.widget)
        self.tableView.setModel(QStandardItemModel(self.tableView))
        self.btnInitTableData.clicked.connect(self.initTableData)
        self.btnReset.clicked.connect(self.reset)


class MainWindow(Ui_MainWindow):
    def __init__(self):
        self.widget = QMainWindow()
        self.setupUi(self.widget)
        self.widget.show()
        self.table = Table(self)
        self.stackedWidget.addWidget(self.table.widget)



app = QApplication([])
win = MainWindow()
app.exec_()
...