PyQtChart 使用 numpy 构建数据时发生内存泄漏如何解决?
想用 PyQtChart 做绘图功能,于是在网上找到个例程,,运行了下功能能实现,,不过在任务管理器里发现这个程序占用的内存一直在增大,,应该是发生了内存泄漏
显示数据是由 series_to_polyline()构建的,里面用到了 numpy,,哪位大神知道这种情况怎么解决?
运行效果:

代码:
import os
import sys
import math
import array
from PyQt5.QtCore import Qt, QTimer, QPointF
from PyQt5.QtGui import QPolygonF
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtChart import QChart, QChartView, QLineSeries
import numpy as np
class DemoWindow(QMainWindow):
def init(self, parent=None):
super(DemoWindow, self).init(parent=parent)
self.plotChart = QChart()
self.plotChart.legend().hide()
self.plotView = QChartView(self.plotChart)
self.setCentralWidget(self.plotView)
self.plotCurve = QLineSeries()
self.plotCurve.setUseOpenGL(True)
self.plotCurve.pen().setColor(Qt.red)
self.plotChart.addSeries(self.plotCurve)
self.plotChart.createDefaultAxes()
self.plotChart.axisX().setLabelFormat('%g')
self.RecvData = array.array('f') # 存储接收到的传感器数据
self.RecvIndx = 0
self.tmrData = QTimer() # 模拟传感器传送过来数据
self.tmrData.setInterval(3)
self.tmrData.timeout.connect(self.on_tmrData_timeout)
self.tmrData.start()
self.tmrPlot = QTimer()
self.tmrPlot.setInterval(100)
self.tmrPlot.timeout.connect(self.on_tmrPlot_timeout)
self.tmrPlot.start()
def on_tmrData_timeout(self):
val = math.sin(2*3.14 / 500 * self.RecvIndx)
self.RecvData.append(val)
self.RecvIndx += 1
def series_to_polyline(self, xdata, ydata):
"""Convert series data to QPolygon(F) polyline
This code is derived from PythonQwt's function named
`qwt.plot_curve.series_to_polyline`"""
size = len(xdata)
polyline = QPolygonF(size)
pointer = polyline.data()
dtype, tinfo = np.float, np.finfo # integers: = np.int, np.iinfo
pointer.setsize(2*polyline.size()*tinfo(dtype).dtype.itemsize)
memory = np.frombuffer(pointer, dtype)
memory[:(size-1)*2+1:2] = xdata
memory[1:(size-1)*2+2:2] = ydata
return polyline
def on_tmrPlot_timeout(self):
self.RecvData = self.RecvData[-1000:]
plotData = self.series_to_polyline(range(len(self.RecvData)), self.RecvData)
self.plotCurve.replace(plotData)
self.plotChart.axisX().setMax(len(plotData))
self.plotChart.axisY().setRange(min(self.RecvData), max(self.RecvData))
if name == ‘main’:
app = QApplication(sys.argv)
window = DemoWindow()
window.show()
window.resize(700, 400)
sys.exit(app.exec_())
PyQtChart 使用 numpy 构建数据时发生内存泄漏如何解决?
你这个 self.RecvData.append(val)只进不出的内存不就越来越大
PyQtChart 使用 numpy 数组时内存泄漏通常是因为数据没有被正确释放。核心问题是 numpy 数组和 Qt 内部数据结构之间的生命周期管理不当。
主要解决方案是确保在更新图表数据时,显式地清理旧的 QLineSeries 或 QScatterSeries 等系列对象,并让 Python 的垃圾回收机制能够正常工作。下面是一个完整的示例:
import sys
import numpy as np
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtChart import QChart, QChartView, QLineSeries
from PyQt5.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.chart = QChart()
self.chart_view = QChartView(self.chart)
self.setCentralWidget(self.chart_view)
# 初始数据
self.update_chart_data()
def update_chart_data(self):
# 清除现有系列
self.chart.removeAllSeries()
# 创建新数据
x = np.linspace(0, 10, 1000000) # 大量数据点
y = np.sin(x)
# 创建新系列
series = QLineSeries()
# 关键:使用 Python 列表而不是 numpy 数组直接传递
# 这样可以避免 Qt 内部持有对 numpy 数组的引用
series.append([(float(x[i]), float(y[i])) for i in range(len(x))])
# 添加到图表
self.chart.addSeries(series)
self.chart.createDefaultAxes()
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
关键点:
- 在更新数据前调用
removeAllSeries()确保旧系列被完全移除 - 将 numpy 数组转换为 Python 列表的元组列表,避免 Qt 内部持有 numpy 数组引用
- 确保系列对象在函数作用域结束后能被垃圾回收
如果数据量特别大,考虑使用 QScatterSeries 并设置 useOpenGL(True) 来利用 GPU 加速,但这需要你的系统支持 OpenGL。
总结:确保正确清理旧系列并断开 numpy 引用。
不是的,你看 on_tmrPlot_timeout()函数第一句
我这里试了一下, 这一行 self.plotCurve.replace(plotData)导致内存持续增长, 注释掉就不会, 怀疑是 pyqt 有问题, 可以用 C++ Qt 再验证下…
不是的,因为把数据构建方式改成下面这样子,其他不变,,就不会有内存泄漏python<br>def series_to_polyline(self, xdata, ydata):<br> polyline = []<br> for i,d in enumerate(ydata):<br> polyline.append(QPointF(i,d))<br> <br> return polyline<br>
不过这样一个点一个点构建数据,我觉可能会比较慢,,不如原来用 numpy 那种方式速度快
原始的 polyline 是 Qt 的 QPolygonF, 你修改后的是 python 的 list, 你再试试在 series_to_polyline 里面完全不使用 numpy 对 QPolygonF 赋值, 内存一样一直涨, 所以排除是 numpy 的问题
def series_to_polyline(self, xdata, ydata):
size = len(xdata)
polyline = QPolygonF(size)
return polyline
多谢指点
试了下,确实如此,,
看来跟 numpy 无关,就是使用 list[QPointF]作为绘图数据时能自动释放,使用 QPolygonF 作为绘图数据时无法自动释放内存,,我去搜下,看能不能手动释放 QPolygonF 占用的内存
用 C++Qt 试了下, 没有问题. 画复杂图形的话, pyqt 直接嵌入 matplotlib 来作图更容易, 相比来说, pyqtchart 太难用了
https://gist.github.com/justou/1fe72187b21af835cf633a37b06e9d74
链接: https://pan.baidu.com/s/15sbdoFpUnbG9rYGnWvtxFg 提取码: cmgj
补充下信息: 我用的 PyQt5 (PyQtChart) 5.11.3, C++Qt 5.10.1
5.9.0 之前这儿似乎是有内存泄露的: https://bugreports.qt.io/browse/QTBUG-58802
楼主是做示波器吗…
不是示波器,是个低速的数据接收、波形显示小软件


