LVGL版本:V8.0.2
平台:ESP32S3
在调试过程中,发现有两个界面,在重复退出再进入时内存会不断增加的吃内存现象,然后做了分析和研究。
1. 样式style吃内存
在主页面,进入simple页面,再退出到主页面,再次进入simple,重复几次,内存就肉眼可见的增加。从开机时主页面5.3KB,增加到了6.6KB。
看下style部分的函数注释就明白了:
/**
* Initialize a style
* @param style pointer to a style to initialize
* @note Do not call `lv_style_init` on styles that are already have some properties
* because this function won't free the used memory just set a default state for the style.
* In other words be sure to initialize styles only once!
*/
void lv_style_init(lv_style_t * style);
/**
* Clear all properties from a style and free all allocated memories.
* @param style pointer to a style
*/
void lv_style_reset(lv_style_t * style);
在创建控件的时候用lv_style_init
创建了很多样式,部分源码移驾这里,但是析构页面的时候样式部分的内存还在,下一次进入又重复创建样式,导致内存泄露。解决办法,析构页面的时候要释放lv_style_init
申请的内存。
解决方案:
-
lv_style_reset
,释放style部分内存
-
- delete页面的父对象,即页面容器对象。此操作会一并delete该父对象的所有子对象
-
- free该页面的数据结构
/*
* brief: 界面销毁
* param: 父对象
* retval: NULL
*/
void winSimpleDestroy(lv_obj_t * pObjParent){
LV_UNUSED(pObjParent);
if(NULL != pWinObj){
lv_style_reset(&pWinObj->label_styles);
lv_style_reset(&pWinObj->style_arc1_bg);
lv_style_reset(&pWinObj->style_arc1_indic);
lv_style_reset(&pWinObj->style_arc1_knob);
lv_style_reset(&pWinObj->style_arc2_bg);
lv_style_reset(&pWinObj->style_arc2_indic);
lv_style_reset(&pWinObj->style_arc2_knob);
lv_style_reset(&pWinObj->style_bar_label1);
lv_style_reset(&pWinObj->style_bar1_bg);
lv_style_reset(&pWinObj->style_bar1_indic);
lv_style_reset(&pWinObj->style_checkbox1);
lv_style_reset(&pWinObj->style_spinner1_bg);
lv_style_reset(&pWinObj->style_spinner1_indic);
lv_style_reset(&pWinObj->style_spinner2_bg);
lv_style_reset(&pWinObj->style_spinner2_indic);
lv_style_reset(&pWinObj->style_line1);
lv_style_reset(&pWinObj->style_led1);
lv_obj_del(pWinObj->pCurrWinObj);
lv_mem_free(pWinObj);
pWinObj = NULL;
}
MEM_PRINT;
}
2. table控件吃内存
在主页面,进入WiFi页面,再退出到主页面,再次进入WiFi页面,重复多次,内存增加,虽然没有simple页面那么快,但是还是会一点点的耗内存。
该WiFi页面也没有用lv_style_init
呀,怎么还会造成内存泄漏呢?
只能一个个控件排查了,最先怀疑的就是table控件咯,因为其他控件在其他页面也使用过,没有内存泄漏,果然,把table屏蔽之后内存不会泄漏了。只能从源码入手分析了。
分析table控件的构造和析构函数,果然发现端倪了
- 构造函数中申请的内存,在析构函数中没有释放完全
static void lv_table_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_table_t * table = (lv_table_t *)obj;
table->col_cnt = 1;
table->row_cnt = 1;
table->col_w = lv_mem_alloc(table->col_cnt * sizeof(table->col_w[0]));
table->row_h = lv_mem_alloc(table->row_cnt * sizeof(table->row_h[0]));
table->col_w[0] = LV_DPI_DEF;
table->row_h[0] = LV_DPI_DEF;
table->cell_data = lv_mem_realloc(table->cell_data, table->row_cnt * table->col_cnt * sizeof(char *));
table->cell_data[0] = NULL;
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_table_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_table_t * table = (lv_table_t *)obj;
/*Free the cell texts*/
uint16_t i;
for(i = 0; i < table->col_cnt * table->row_cnt; i++) {
if(table->cell_data[i]) {
lv_mem_free(table->cell_data[i]);
table->cell_data[i] = NULL;
}
}
if(table->cell_data) lv_mem_free(table->cell_data);
if(table->row_h) lv_mem_free(table->row_h);
// if(table->col_w) lv_mem_free(table->col_w); // fix | slim20221007 > 会导致内存泄露
}
解决方案:
加入如下patch就好了,重复进出WiFi页面,测试多次,内存稳定了
if(table->col_w) lv_mem_free(table->col_w); // fix | slim20221007 > 会导致内存泄露