像OOM打印一样,查看各进程的内存信息,追踪内存泄漏

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内容物理内存使用情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值