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介绍

Linux内存从0到1学习笔记(9.7 内存优化调试之page_owner内存分配堆栈详解)---更新中

Linux内存从0到1学习笔记(11.2 内存优化方案之内存压缩zram)