记录一下最近一段时间基于炬芯平台跑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);
}
}
}
3623

被折叠的 条评论
为什么被折叠?



