分析这份kernel日志,系统卡死发生OOM的原因
这份内核日志显示系统在时间戳 [23010.193833] 发生了内核恐慌(Kernel Panic),原因是内存耗尽(Out of Memory, OOM),且没有可杀死的进程("Out of memory and no killable processes..."),最终导致系统死锁("System is deadlocked on memory")。以下是对日志的详细分析,找出OOM的具体原因以及系统卡死的原因。
关键信息提取
时间和触发点:
时间戳 [23010.193833],线程 T17593(BootAnimation)触发了OOM。
调用栈显示问题发生在Mali GPU驱动(mali_kbase_mt6768_r49)的内存分配函数 kbase_mem_pool_alloc_pages 中。
内存状态:
总内存:1048576 pages RAM(约4GB,假设页面大小为4KB)。
可用内存:
DMA32 free: 512008kB(约500MB)。
Normal free: 1096kB(约1MB)。
总可用内存约513MB。
CMA内存:free_cma: 494976kB(约483MB),占总可用内存的大部分。
交换空间:
Free swap: 3075604kB(约3GB)。
Total swap: 3418196kB(约3.3GB)。
内存分配失败:
调用栈显示 kbase_mem_alloc -> __alloc_pages_slowpath -> out_of_memory,表明GPU驱动尝试分配物理页面失败。
系统状态:
内核版本:6.6.30-android15-8。
硬件:MT6769V/CB(联发科MT6769,可能为Helio G80/G85)。
OOM发生在用户态进程 BootAnimation(PID 17593)通过 ioctl 调用GPU驱动时。
Slab内存:
slab_unreclaimable: 701744kB(约686MB)。
具体项:
kmalloc-128: 2155876kB(约2GB)。
kmalloc-64: 505068kB(约493MB)。
OOM原因分析
1. 内存分配需求与可用内存不匹配
现象:
DMA32 区域有500MB可用内存,其中483MB是CMA(Contiguous Memory Allocator)内存。
Normal 区域仅剩1MB可用。
分析:
Mali GPU驱动(kbase_mem_pool_alloc_pages)尝试分配连续物理内存页面。
CMA内存虽然可用,但可能受限于以下因素:
CMA使用限制:CMA内存通常为特定设备(如GPU、相机)预留,普通内核分配可能无法直接使用,除非明确请求(通过 GFP_DMA 或类似标志)。
碎片化:即使有500MB总可用内存,可能是分散的页面,无法满足GPU需要的连续大块内存。
调用栈中的 MTKAllocPage 和 kbase_mem_pool_alloc_pages 表明这是一个大页面分配请求(可能为4MB或更大),而系统无法从当前可用内存中满足。
2. BootAnimation的高内存需求
现象:
BootAnimation(PID 17593)的内存使用:
total_vm: 3037228 pages(约11.6GB虚拟内存)。
rss: 25360 pages(约99MB常驻内存)。
pgtables_bytes: 991232 bytes(约1MB页面表)。
调用栈显示它通过 ioctl 调用GPU驱动分配内存。
Mali设备报告:
mali 13040000.mali: OOM notifier: dev mali0 111932 kB
mali 13040000.mali: OOM notifier: tsk bootanimation ... 98808 kB
Mali设备已使用约109MB,BootAnimation 使用约96MB。
分析:
启动动画(BootAnimation)通常涉及GPU渲染,可能需要分配大量显存(如帧缓冲区或纹理)。
这次分配可能是额外显存请求,但因内存不足失败。
3. OOM Killer未触发
现象:
日志显示 "Out of memory and no killable processes...",没有进程被杀死。
分析:
Linux的OOM Killer通常会根据 oom_score_adj 和内存使用选择牺牲进程,但这里未发生。
检查 Tasks state:
BootAnimation 的 oom_score_adj = 0(默认值)。
许多关键系统进程(如 init、lmkd)有负值(如 -1000),优先级更高,无法被杀。
可能原因:
所有进程不可杀:系统认为当前运行的进程(如 surfaceflinger、binder 等)都不可牺牲。
CMA限制:OOM Killer无法释放CMA内存,导致无法缓解压力。
死锁:内存分配卡在GPU驱动中,OOM Killer未被正确触发。
4. Swap未有效利用
现象:
交换空间剩余3GB,但 swapents(每个进程的交换页面)普遍较低(例如 BootAnimation 仅4828页,约18MB)。
pages in swap cache: 0。
分析:
系统未将内存压力转移到交换空间。
可能原因:
Swap未启用或配置不当:尽管有3GB可用swap,但没有页面被换出。
ZRAM限制:如果使用zram(日志未明确显示),压缩效率可能不足,或zram容量已满。
匿名内存不足:active_anon: 464kB, inactive_anon: 1204kB,匿名内存极少,大部分内存可能被文件缓存或显存占用。
5. Slab内存占用过高
现象:
slab_unreclaimable: 701744kB(约686MB)。
具体项:
kmalloc-128: 2155876kB(约2GB)。
kmalloc-64: 505068kB(约493MB)。
vm_area_struct: 8833kB(约8.6MB)。
分析:
不可回收的slab内存占用了大量RAM(约2.7GB),远超可用内存。
kmalloc-128 和 kmalloc-64 是小块内存分配,可能与内核对象(如网络、文件系统、驱动)有关。
GPU驱动(mali_kbase)可能也贡献了部分不可回收内存,导致系统无法释放足够空间。
kmalloc-128 的异常高占用(2GB)可能是内存泄漏或驱动bug的结果。
系统卡死的根本原因
综合分析,系统卡死的直接原因是:
GPU驱动的连续内存分配失败:
BootAnimation 通过 ioctl 请求Mali驱动分配大块连续内存(如帧缓冲区)。
尽管有513MB可用内存(包括483MB CMA),但碎片化或CMA限制导致无法满足请求。
OOM Killer失效:
系统无法找到可杀进程(可能是关键进程保护或配置问题)。
CMA内存未被释放,普通内存仅剩1MB,无法缓解压力。
内存管理失衡:
Slab占用2.7GB不可回收内存(尤其是 kmalloc-128 的2GB异常值),限制了可用空间。
Swap未被有效利用,匿名内存未换出。
死锁触发:
__alloc_pages_slowpath 调用 out_of_memory,但无解后进入 panic,导致内核停止。
日志中的其他线索
电池和充电状态:
is_charging=0,vbat_out=38680(约3.87V),电池电量55%(soc:5310)。
未充电,可能排除电源管理干扰。
TCPC(USB Type-C)活动:
频繁的 AttachWait.SNK -> Unattached.SRC 切换,可能是USB设备插拔,但与OOM无直接关联。
Mali OOM通知:
mali 13040000.mali: OOM notifier 显示GPU内存压力,但未触发有效回收。
解决建议
优化CMA使用:
检查CMA配置(139264 pages cma reserved ≈ 544MB),确保GPU驱动能正确使用CMA。
调整 vm.min_free_kbytes,增加非CMA可用内存。
启用Swap:
确保zram或其他swap机制正常工作,增加 vm.swappiness(默认可能是0)。
调整OOM策略:
修改 BootAnimation 的 oom_score_adj,降低其优先级。
检查 lmkd(低内存杀手)配置,确保其能及时杀死非关键进程。
减少Slab占用:
分析 kmalloc-128 和 kmalloc-64 的来源,排查内存泄漏或驱动bug。
GPU驱动优化:
检查Mali驱动是否过度请求连续内存,考虑分块分配。
结论
系统因 BootAnimation 的GPU内存分配失败触发OOM,结合碎片化、CMA限制、Slab占用高(尤其是 kmalloc-128 的异常2GB)和Swap未用,导致无可用内存且OOM Killer失效,最终死锁。解决需要从内存配置、Slab管理、驱动优化入手。
https://x.com/i/grok/share/oZCASr9cHXVBwafNbYcBGswvj