LVGL开发遇到的内存泄露问题

 记录一下最近一段时间基于炬芯平台跑monkey测试遇到的关于lvgl8.3内存泄露导致死机问题。

现象:反复进入同一页面后,出现内存不足的死机重启现象。

一、样式资源泄漏 

分析:页面创建时使用lv_style_init初始化控件,但是页面释放时没有调用lv_style_reset去释放样式。手动去进入和退出该页面,通过使用炬芯内存打印命令查看内存状态,发现可用内存持续减少,最终导致设备因内存不足而重启。

//在函数内创建动态样式
void create_chart(void) 
{
    lv_obj_t *chart = lv_chart_create(lv_scr_act());
    ...

    lv_style_t *line_style = malloc(sizeof(lv_style_t)); // 分配内存
    lv_style_init(line_style); // 初始化样式
    lv_style_set_bg_color(line_style, lv_color_hex(0xFF0000));
    
    lv_obj_t *line = lv_line_create(chart);
    lv_obj_add_style(line, line_style, 0); // 关联样式
    ...
    
    // 函数结束时未释放line_style导致泄漏
}

优化:

1.静态样式

样式定义为全局,创建控件时复用。

// 全局样式定义
static lv_style_t chart_line_style;

void init_styles(void) 
{
    lv_style_init(&chart_line_style);
    lv_style_set_line_color(&chart_line_style, lv_color_hex(0xFF0000), 0);
}

void create_chart(void) 
{
    lv_obj_t *chart = lv_chart_create(lv_scr_act());
    lv_obj_t *line = lv_line_create(chart);
    
    // 复用全局样式
    lv_obj_add_style(line, &chart_line_style, LV_PART_MAIN);
}

2.动态样式

动态管理该样式,页面卸载时调用lv_style_reset去释放。

typedef struct 
{
    lv_obj_t *chart;
    lv_style_t *line_style;
} chart_context_t;

void chart_delete_cb(lv_event_t *e) 
{
    chart_context_t *ctx = lv_event_get_user_data(e);
    if(ctx->line_style) 
    {
        lv_style_reset(ctx->line_style); // 释放样式资源
        lv_free(ctx->line_style);        // 释放内存
    }
    lv_free(ctx); // 释放上下文
}

void create_chart(void) 
{
    chart_context_t *ctx = lv_malloc(sizeof(chart_context_t));
    
    ctx->chart = lv_chart_create(lv_scr_act());
    ctx->line_style = lv_malloc(sizeof(lv_style_t));
    lv_style_init(ctx->line_style);
    lv_style_set_line_color(ctx->line_style, lv_color_hex(0xFF0000), 0);
    
    lv_obj_t *line = lv_line_create(ctx->chart);
    lv_obj_add_style(line, ctx->line_style, LV_PART_MAIN);
    
    // 绑定删除事件
    lv_obj_add_event_cb(ctx->chart, chart_delete_cb, LV_EVENT_DELETE, ctx);
}

二、内存碎片化

分析:切换子页面时频繁使用lv_obj_del清除页面父对象导致内存碎片。

同一页面下存在多个子页面,在切换不同子页面时,每次会去删除父对象下的所有控件。

void show_subpage(lv_obj_t *scr, subpage_data_t *data) 
{
    // 错误:每次切换都删除父对象
    if(data->obj) 
    {
        lv_obj_del(data->obj); // 完全删除对象
        data->obj = NULL;
    }
    
    // 重新创建整个页面
    data->obj = lv_obj_create(scr);

    // ...创建子控件...
}

频繁的使用lv_obj_del去删除所有子控件,然后再重新创建父对象,会产生内存碎片,跑monkey测试会出现内存不足导致死机重启。

优化:

1.共用父对象

切换子页面时,使用lv_obj_clean去删除所有子控件,保留父对象。

void show_subpage(lv_obj_t *scr, subpage_data_t *data) 
{
    if(!data->obj) 
    {
        // 首次创建容器
        data->obj = lv_obj_create(scr);
    }
    else 
    {
        // 仅清除内容
        lv_obj_clean(data->obj);
    }
    
    // ...创建子控件...
    lv_obj_t *label = lv_label_create(data->obj);
    lv_label_set_text(label, "Current Page Content");
}

2.页面预加载

一次性加载所有子页面,然后通过隐藏的方式来显示需要的子页面。

#define MAX_SUBPAGES (3)

typedef struct 
{
    lv_obj_t *container;
    bool initialized;
} subpage_t;

subpage_t subpages[MAX_SUBPAGES];

void init_subpages(lv_obj_t *parent) 
{
    for(int i = 0; i < MAX_SUBPAGES; i++) 
    {
        subpages[i].container = lv_obj_create(parent);
        subpages[i].initialized = false;
        lv_obj_add_flag(subpages[i].container, LV_OBJ_FLAG_HIDDEN);
    }
}

void show_subpage(int index) 
{
    for(int i = 0; i < MAX_SUBPAGES; i++) 
    {
        if(i == index) 
        {
            if(!subpages[i].initialized) 
            {
                init_page_content(subpages[i].container);
                subpages[i].initialized = true;
            }
            lv_obj_clear_flag(subpages[i].container, LV_OBJ_FLAG_HIDDEN);
        } 
        else 
        {
            lv_obj_add_flag(subpages[i].container, LV_OBJ_FLAG_HIDDEN);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值