如何修复动态折线图中的错误和内存泄漏

0 投票
1 回答
33 浏览
提问于 2025-04-14 16:25

我正在尝试创建一个可以动态变化的图表,能够显示最新的数值。可是,我遇到了一个错误信息,并且还出现了内存泄漏,我不知道是什么原因。你能告诉我你知道的原因吗?

错误信息:

[ERROR:flutter/flow/layers/transform_layer.cc(23)] TransformLayer is constructed with an invalid matrix.

内存泄漏
通过使用top命令确认了内存泄漏。flet的内存随着时间的推移而增加。

我的代码如下:

import flet as ft
import schedule
import time
import random

vx_val = [0]*1000 # 10ms*100*1000=1000s
vx_time = [round(i*0.1,1) for i in range(-1000+1, 0+1, 1)] # 10ms*100*1000=1000s

time_start = time.perf_counter()
elapsed_time = time.perf_counter() - time_start

class GuiViewer_graph(ft.UserControl):

    ref_vx_linechartdata = ft.Ref[ft.LineChartData]()

    def __init__(self):
        super().__init__()

    def build(self):
        
        chart_vx = ft.LineChartData(
            data_points=[],
            stroke_width=5,
            color=ft.colors.BLUE,
            curved=False,
            stroke_cap_round=True,
            ref=self.ref_vx_linechartdata,
        )
        
        for i in range(0, len(vx_val)):
            chart_vx.data_points.append(
                ft.LineChartDataPoint(x=vx_time[i], y=vx_val[i])
            )
        
        vx_graph=ft.LineChart(
            data_series=[
                chart_vx,
            ],
            border=ft.border.all(3, ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE)),
            horizontal_grid_lines=ft.ChartGridLines(
                interval=20, color=ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE), width=1
            ),
            # vertical_grid_lines=ft.ChartGridLines(
            #     interval=10, color=ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE), width=1
            # ),
            left_axis=ft.ChartAxis(
                title=ft.Text('velocity[km/h]', weight=ft.FontWeight.BOLD),
                labels_size=40,
                labels_interval=20,
            ),
            bottom_axis = ft.ChartAxis(
                title=ft.Text('time[sec]', weight=ft.FontWeight.BOLD),
                labels_size=40,
                labels_interval=10,
            ),
            min_y=0,
            max_y=180,
            interactive=True,
            animate=True,
            #expand=True,
        )

        table = ft.Container(
            content=ft.Column(
                scroll=True,
                controls=[
                    # speed graph,
                    ft.Container(
                        content=ft.Column(
                            horizontal_alignment = ft.CrossAxisAlignment.CENTER,
                            controls=[
                                ft.Text('Speed', size=20, weight=ft.FontWeight.BOLD),
                                vx_graph,
                            ],
                        ),
                        margin=30,
                        expand=True,
                    ),
                ],
                #expand=True,
            ),
        )
        
        return table
    
    def update(self):
        self.control.update()

def gui(page: ft.Page):
    page.title = "Viewer"
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    main_window = ft.Container(
        content=GuiViewer_graph()
    )

    page.add(main_window)
    page.update()

    def gui_update(page):
            
            global time_start, elapsed_time, vx_val, vx_time

            # Elapsed Time calc
            elapsed_time = time.perf_counter() - time_start

            # graph data update
            vx_current = random.uniform(0, 160)
            vx_val[0:-1] = vx_val[1:]
            vx_val[-1] = vx_current
            vx_time[0:-1] = vx_time[1:]
            vx_time[-1] = elapsed_time

            for i in range(0,len(vx_val)):
                # Memory leak point !!
                GuiViewer_graph.ref_vx_linechartdata.current.data_points[i] = ft.LineChartDataPoint(x=vx_time[i], y=vx_val[i])
            
            GuiViewer_graph.ref_vx_linechartdata.current.update()

 

    # Sceduler
    every_second=0.1
    schedule.every(every_second).seconds.do(gui_update,page=page)

    while True:
        schedule.run_pending()
        time.sleep(0.1)

if __name__ == '__main__':
    ft.app(target=gui)

1 个回答

0

与其在循环中一个一个地更新数据点,不如一次性清空并更新整个数据列表。这样做可以更高效。记得要好好管理引用,以免造成内存泄漏。

def gui_update(page):
    global time_start, elapsed_time, vx_val, vx_time

    # Elapsed Time calc
    elapsed_time = time.perf_counter() - time_start

    # graph data update
    vx_current = random.uniform(0, 160)
    vx_val = vx_val[1:] + [vx_current]
    vx_time = vx_time[1:] + [elapsed_time]

    # Update chart data
    chart_data = GuiViewer_graph.ref_vx_linechartdata.current
    chart_data.data_points = [ft.LineChartDataPoint(x=x, y=y) for x, y in zip(vx_time, vx_val)]
    chart_data.update()

撰写回答