page owner是内核的内存调试的一个功能,可以打印出每一个page的分配栈。因此当使用直接分配页(__alloc_pages)的方式分配内存发生泄露时,使用page owner特别合适。
开启选项:
Kernel hacking ---> Memory Debugging ---> [*] Track page owner
打开上述选项后,page owner将编译进内核,但是要打开此功能,还需要在内核命令行参数添加page_owner=on。
启动后,将/sys/kernel/debug/page_owner到被到/tmp目录,并使用tftp传输出来,打开是一个文本文件,记录了每一个page的分配栈,如下:
Page allocated via order 0, mask 0x4000(__GFP_RETRY_MAYFAIL), pid 0, ts 0 ns, free_ts 0 ns
PFN 264212 type Unmovable Block 129 type Unmovable Flags 0x0(zone=0)
__alloc_pages+0x134/0x1064
__rb_allocate_pages+0xc4/0x1d8
rb_allocate_cpu_buffer+0x158/0x22c
__ring_buffer_alloc+0x100/0x1a8
allocate_trace_buffer+0x24/0xc8
early_trace_init+0x1c0/0x418
start_kernel+0x408/0x6ac
0x0
为了统计同一个栈分配的页的次数,编写一个统计工具,如参考[2]。使用此工具生成统计数据,按照分配的内存大小降序排列:
$ ./page_owner_stat -o result.18024.free /work/tftproot/page_owner.18024
times 878 order 3 mask 0xd2a20
__alloc_pages+0x134/0x1064
page_frag_alloc_align+0x84/0x180
__netdev_alloc_skb+0x158/0x190
ath11k_ce_rx_post_pipe+0x1c0/0x364 [ath11k]
ath11k_ce_per_engine_service+0x2d8/0x38c [ath11k]
ath11k_pci_ce_tasklet+0x18/0x34 [ath11k_ahb]
tasklet_action_common.constprop.0+0xc8/0xf0
__do_softirq+0x13c/0x444
times 739 order 3 mask 0xd2a20
__alloc_pages+0x134/0x1064
page_frag_alloc_align+0x84/0x180
__netdev_alloc_skb+0x158/0x190
syn_dp_rx_refill+0x120/0x1bc [nss_dp]
syn_dp_napi_poll_rx+0x2c/0x84 [nss_dp]
__napi_poll+0x28/0x208
net_rx_action+0xe4/0x270
__do_softirq+0x13c/0x444
times 392 order 3 mask 0xd2a20
__alloc_pages+0x134/0x1064
page_frag_alloc_align+0x84/0x180
__netdev_alloc_skb+0x158/0x190
ath11k_ce_rx_post_pipe+0x1c0/0x364 [ath11k]
ath11k_ce_per_engine_service+0x2d8/0x38c [ath11k]
ath11k_ahb_ce_tasklet+0x24/0x8c [ath11k_ahb]
tasklet_action_common.constprop.0+0xc8/0xf0
__do_softirq+0x13c/0x444
...
最好是抓去一下内存富余和内存紧张两种情况下的page owner数据,生成统计数据,进行对比,即可知道哪些地方消耗了大量的内存。
如上,前2位的统计数据是多出来的,因此就定位了到是哪里消耗了内存,然后在根据代码进行分析。
统计工具在比较栈的时候,只比较到__do_softirq,这很重要,因为软中断可能在任何地方发生,不进行这个处理的话,同一个分配函数,所产生的栈是不同的。
参考:
[1] https://www.kernel.org/doc/html/latest/vm/page_owner.html
[2] https://insidelinuxdev.net/~yuanjianpeng/project/page_owner_stat