3、内存调试基础:LVGL内存分配机制、内存泄漏检测方法、内存池配置检查
内存问题,是嵌入式LVGL开发里最让人头疼的坑之一。我见过太多项目,界面画到一半突然卡死,或者运行几小时后莫名其妙花屏。十有八九,都是内存惹的祸。
这一章,咱们就把LVGL的内存机制掰开揉碎。你搞懂了它,调试起来心里就有底了。
3.1 LVGL的内存分配机制
LVGL默认使用动态内存分配。说白了,就是它自己管着一块内存池,你需要控件、图片、字体时,就从池子里拿。用完再还回去。
这个池子有多大?由你决定。在 lv_conf.h 里有个关键宏:
#define LV_MEM_SIZE (32U * 1024U) /* 32KB内存池 */
我个人习惯,先给个保守值。比如屏幕是320x240,16位色,一个全屏缓冲区就占150KB。那内存池至少得256KB起步。你想想看,如果只给32KB,随便加载一张图片就爆了。
LVGL内部用了几种分配策略:
- 标准malloc/free:如果你没定义自定义分配器,LVGL就用C库的malloc。这在PC上没问题,但在单片机上,malloc容易产生碎片。
- LVGL内置分配器:推荐用这个。它用了一个简单的内存块链表,分配速度快,碎片少。在
lv_conf.h里开启:
#define LV_MEM_CUSTOM 0 /* 使用LVGL内置分配器 */
我在项目中遇到过,用标准malloc跑了一个月,内存碎片导致分配失败。换成内置分配器后,稳如老狗。
3.2 内存泄漏检测方法
内存泄漏,就是申请了内存没释放。LVGL里最常见的泄漏点:
- 创建了控件,但忘记删除
- 加载了图片,但没调用
lv_img_cache_invalidate_src() - 动态分配的字符串或样式,没释放
怎么检测?LVGL自带了一个神器:lv_mem_monitor_t。
lv_mem_monitor_t mon;
lv_mem_monitor(&mon);
LV_LOG_USER("已使用: %d bytes, 空闲: %d bytes, 碎片: %d%%",
mon.total_size - mon.free_size,
mon.free_size,
mon.frag_pct);
把这个打印放在主循环里,每隔几秒输出一次。如果已使用内存持续增长,恭喜你,泄漏了。
关键指标:碎片率超过20%就要警惕了。我见过一个项目,碎片率到了35%,分配一个100字节的控件都失败。
还有一个更粗暴的方法:在 lv_conf.h 里开启内存统计:
#define LV_MEMCPY_MEMSET_STD 1
#define LV_MEM_LOG 1
这样每次分配和释放都会打印日志。你可以在串口里搜 alloc 和 free,看看数量是否匹配。
我的小技巧:写一个测试函数,反复创建和删除同一个控件。如果内存只增不减,那肯定有泄漏。我曾经用这个方法,半天就揪出了三个泄漏点。
3.3 内存池配置检查
配置内存池,不是拍脑袋定个大小就完事了。你得检查几个关键点:
| 检查项 | 说明 | 常见问题 |
|---|---|---|
| 内存池大小 | LV_MEM_SIZE | 设太小,运行中分配失败 |
| 对齐方式 | LV_MEM_ATTR 和 LV_MEM_ADR | 不对齐会导致硬件异常 |
| 自定义分配器 | LV_MEM_CUSTOM | 用标准malloc容易碎片 |
| 缓冲区大小 | LV_VER_RES_MAX * LV_HOR_RES_MAX * 2 | 太小会频繁刷新,性能下降 |
嗯,这里要注意。内存池的起始地址,最好4字节对齐。有些MCU要求8字节对齐。不对齐的话,访问内存会触发硬件错误。我踩过这个坑,查了两天才发现是地址没对齐。
怎么检查对齐?加一行代码:
if ((uint32_t)lv_mem_buf & 0x3) {
LV_LOG_ERROR("内存池未4字节对齐!");
}
还有一个容易被忽略的点:LVGL的显示缓冲区。它不占用内存池,但占用RAM。如果你用双缓冲,每个缓冲区大小是 LV_HOR_RES_MAX * LV_VER_RES_MAX * 2 字节。320x240的屏幕,16位色,一个缓冲区就是150KB。两个就是300KB。加上内存池,总RAM消耗轻松超过512KB。
警告:别把内存池和显示缓冲区设得太大,超过MCU的RAM总量。否则程序直接跑不起来。我曾经在STM32F407上试过,RAM只有192KB,我设了256KB的内存池,结果上电就死。
最后,给你一个检查清单。每次移植LVGL时,对着过一遍:
- 确认
LV_MEM_SIZE不超过MCU可用RAM - 确认内存池地址对齐(4字节或8字节)
- 开启
LV_MEM_LOG观察分配释放是否平衡 - 运行压力测试:反复创建/删除控件,监控内存变化
- 检查碎片率,超过20%考虑增大内存池或改用内存管理算法
做到这几点,内存问题基本就能防住八成。剩下的两成,靠经验和日志慢慢排查。别急,调试本身就是个手艺活。