linux中当内存不够时,可能会触发OOM(out of mem),一般系统出现OOM,可能是系统中有进程存在内存泄漏。当系统出OOM时,会有各进程的内存信息和OOM评分,评分高的task_struct会被kill掉。
为了追踪内存泄漏是哪个进程造成,需要像OOM的信息一样,从开机的时候的内存信息,和OOM时的内存信息作比较,差量最大的进程就很大可能是出内存泄漏。
我们写一个KO,来给用户侧查看各进程的内存信息;提供proc文件task_meminfo,给用户cat。
上代码:
#include <linux/oom.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/sched/coredump.h>
#include <linux/sched/task.h>
#include <linux/swap.h>
#include <linux/timex.h>
#include <linux/jiffies.h>
#include <linux/cpuset.h>
#include <linux/export.h>
#include <linux/notifier.h>
#include <linux/memcontrol.h>
#include <linux/mempolicy.h>
#include <linux/security.h>
#include <linux/ptrace.h>
#include <linux/freezer.h>
#include <linux/ftrace.h>
#include <linux/ratelimit.h>
#include <linux/kthread.h>
#include <linux/init.h>
#include <linux/mmu_notifier.h>
#include <asm/tlb.h>
#include <trace/events/oom.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
struct task_struct *find_lock_task_mm(struct task_struct *p)
{
struct task_struct *t;
rcu_read_lock();
for_each_thread(p, t) {
task_lock(t);
if (likely(t->mm))
goto found;
task_unlock(t);
}
t = NULL;
found:
rcu_read_unlock();
return t;
}
int task_meminfo_show(struct seq_file *seq_filp, void *data)
{
struct task_struct *p;
struct task_struct *task;
seq_printf(seq_filp, "Tasks state (memory values in pages):\n");
seq_printf(seq_filp, "[ pid ] uid tgid total_vm rss file anon shm pgtables_bytes swapents oom_score_adj name\n");
rcu_read_lock();
for_each_process(p) {
task = find_lock_task_mm(p);
if (!task) {
/*
* This is a kthread or all of p's threads have already
* detached their mm's. There's no need to report
* them; they can't be oom killed anyway.
*/
continue;
}
seq_printf(seq_filp, "[%7d] %5d %5d %8lu %8lu %8lu %8lu %8lu %8ld %8lu %5hd %s\n",
task->pid, from_kuid(&init_user_ns, task_uid(task)),
task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
get_mm_counter(task->mm, MM_FILEPAGES),
get_mm_counter(task->mm, MM_ANONPAGES),
get_mm_counter(task->mm, MM_SHMEMPAGES),
mm_pgtables_bytes(task->mm),
get_mm_counter(task->mm, MM_SWAPENTS),
task->signal->oom_score_adj, task->comm);
task_unlock(task);
}
rcu_read_unlock();
return 0;
}
int task_meminfo_open(struct inode *p_node, struct file *flip)
{
return single_open(flip, task_meminfo_show, NULL);
}
static struct file_operations task_meminfo_fops = {
.owner = THIS_MODULE,
.open = task_meminfo_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
static struct proc_dir_entry *task_meminfo = NULL;
static __init int task_mm_info_init(void)
{
task_meminfo = proc_create("task_meminfo", S_IRUGO, NULL, &task_meminfo_fops);
if (task_meminfo == NULL)
{
printk("task_mm_info_init: creat /proc/task_meminfo node failed!!!\n");
return -EINVAL;
}
return 0;
}
static __exit void task_mm_info_exit(void)
{
proc_remove(task_meminfo);
}
module_init(task_mm_info_init);
module_exit(task_mm_info_exit);
MODULE_VERSION("0.01");
MODULE_AUTHOR("zfj.");
MODULE_DESCRIPTION("task mem info");
MODULE_LICENSE("GPL");
insmod后会在/proc/下生成节点task_meminfo, cat结果
解释下各项:
total_vm: 总虚拟内存,单位page(4K)。
rss: 目前占有的物理页。
/下面三项为自己加的/
file:文件mmap内存
anon:匿名页。
shmem:共享内存
另外在/proc/${pid}/status查看内存信息。
查看rss内容物理内存使用情况。