Linux内存从0到1学习笔记(九,内存优化调试之三 - 使用page owner调试内存黑洞)
Posted 高桐@BILL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内存从0到1学习笔记(九,内存优化调试之三 - 使用page owner调试内存黑洞)相关的知识,希望对你有一定的参考价值。
一、内存黑洞
在内核中有一些内存是以页为单位被申请走,并且在内核中无法通过/proc/meminfo来排查这部分内存的去向。通常情况下是设备驱动或者内核模块调用kmalloc申请了大于8K(slab是4M,这里是以slub为例子)的连续物理内存,或者调用alloc_page
直接向伙伴系统申请物理内存,因此没有将这部分内存统计在内核的相关字段中。
/proc/meminfo等常规手段无法统计到的这部分内存我们称之为内存黑洞。内存黑洞的计算方法如下:
uncount memory(内存黑洞) = MemTotal - MemFree - Active - Inactive - Slab - KernelStack - PageTables
二、PageOwner
PageOwner用于跟踪每个内存页被谁分配走了。它可以用来分析内存泄漏,找出内存占用者后者。当分配内存时,分配的调用栈信息和内存页顺序会为每个内存页保存下来。当我们需要了解所有内存页的状态时,我们可以读取这些节点信息来分析内存分配的详细细节。
PagetOwner可以用于多种需求,如通过每个内存页的gfp标识进行准确的碎片统计;
PageOwner在内核中已经得到实现,但默认情况下关闭,如果需要使用的话,需要YES相关的配置项以编译到内核当中。且需要在开机cmdline中添加“page_owner=on”进行使能。如果已经将page owner编译到内核当中,但在运行时状态下并没有使能,其开销是微不足道的。运行时不使能page owner并不会请求内存存储内存页申请的相关信息。
打开pageowner前后对比如下:
- 默认关闭pageowner:: text data bss dec hex filename 48392 2333 644 51369 c8a9 mm/page_alloc.o - 使能pageowner:: text data bss dec hex filename 48800 2445 644 51889 cab1 mm/page_alloc.o 6662 108 29 6799 1a8f mm/page_owner.o 1025 8 8 1041 411 mm/page_ext.o
page owner的详细用法如下;
2.1 内核中打开pageowner编译选项
CONFIG_PAGE_OWNER=y
2.2 编译用户空间帮助工具
cd tools/vm
make page_owner_sort
2.3 使能pageowner
需要添加“page_owner=on”到启动cmdline中,在不同平台有着不同的宏控,如下:
2.3.1 MTK平台
CONFIG_PAGE_OWNER_SLIM=y
2.3.2 Qcom平台
CONFIG_PAGE_OWNER_SLIM=y
2.3.3 或直接修改cmdline
adb reboot-bootloader
fastboot oem append-cmdline page_owner=on
fastboot continue
2.3.4 或直接修改代码
linux_mainline-5.17.0/mm/page_owner.c
---static bool page_owner_enabled = false;
+++static bool page_owner_enabled = true;
DEFINE_STATIC_KEY_FALSE(page_owner_inited);
或
linux-4.19.236/mm/page_owner.c
---static bool page_owner_disabled = true;
+++static bool page_owner_disabled = false;
DEFINE_STATIC_KEY_FALSE(page_owner_inited);
static depot_stack_handle_t dummy_handle;
static depot_stack_handle_t failure_handle;
static depot_stack_handle_t early_handle;
2.4 page owner数据解析
2.4.1 获取page_owenr结点信息
获取page_owner节点信息,并保存到page_owner_full.txt中。
cat /sys/kernel/debug/page_owner > page_owner_full.txt
page_owner_full.txt内容如下:
Page allocated via order XXX, ...
PFN XXX ...
// Detailed stack
Page allocated via order XXX, ...
PFN XXX ...
// Detailed stack
Page allocated via order 0
[0xc0146f01] kmem_getpages+49
[0xc014846d] cache_grow+173
[0xc0148aac] cache_alloc_refill+460
[0xc0118a8f] copy_files+431
[0xc0148ff5] kmem_cache_alloc+149
[0xc011986b] copy_process+3051
[0xc01199d1] fork_idle+65
[0xc041824a] do_boot_cpu+42
2.4.2 使用page_owner_sort解析
./page_owner_sort page_owner_full.txt sorted_page_owner.txt
通过page_owner_sort工具的处理后,会生成一个sorted_page_owner.txt文件,其内容如下:
XXX times, XXX pages:
Page allocated via order XXX, ...
// Detailed stack
page_owner_sort工具会过滤到PFN行,并将剩余的行读取到缓存中,然后通过正则表达式来提取内存页order值,时间等信息。最终会根据时间进行排序。
如果你想根据buf中的order,可以配合“-m”参数使用。其他参数如(与kernel版本有关):
-a
通过内存分配时间来排序。
-m
通过分配的内存。
-p
通过进程pid。
-P
通过tgid来排序。
-n
通过任务cmmand名称来排序
-r
通过内存释放事件排序。
-s
通过调用栈调用栈。
-t
默认通过时间来排序。
其他
其他版本如linux-4.19.236;
cd tools/vm
make page_owner_sort
cat /sys/kernel/debug/page_owner > page_owner_full.txt
grep -v ^PFN page_owner_full.txt > page_owner.txt ./page_owner_sort page_owner.txt sorted_page_owner.txt
以上是关于Linux内存从0到1学习笔记(九,内存优化调试之三 - 使用page owner调试内存黑洞)的主要内容,如果未能解决你的问题,请参考以下文章
Linux内存从0到1学习笔记(九,内存优化调试之一 - kswapd0)
Linux内存从0到1学习笔记(9.6,内存优化调试之page_owner拆解)
Linux内存从0到1学习笔记(9.5,内存优化调试之记录pid到page_owner)
Linux内存从0到1学习笔记(9.10 内存优化调试之panic_on_oom介绍