Linux 内存管理

内核中分配内存不像在用户态那么容易。内核一般不能睡眠,而且处理内存分配错误对内核来说也并非易事。由于这类因素存在,导致内核中获取内存要比在用户控件复杂很多。本文参考《Linux 内核设计与实现》,大致梳理一下Linux内核的内存管理。简单总结下内存管理的基本单位—页,内存管理方式—按区划分,以及避免内存碎片的机制—slab 层等。

内核把 物理页 作为内存管理的基本单位,用struct page结构表示系统中的每个 物理页

1
2
3
4
5
6
7
8
9
10
11
/*定义在 <linux/mm_types.h> */
struct page{
unsigned long flag;
atomic_t _count;
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void* virtual;
};

【转】2008 年北京奥运会到底给我们留下了什么?

饶谨和王兴两人同为龙岩人和清华校友,两个人的关系很好。王兴回国办校内网网,第一个服务器还是在饶谨的宿舍里架设的。08年的时候,饶谨创办了“爱国的”四月网,专门搜集西方媒体关于中国的不实报道,为奥运会保驾护航,王兴在运营“带路的”饭否网,一大堆敏感词在饭否上面开通了账号。


老罗的牛博网也聚集了很多有趣的人,每一个人都是他的朋友,但是方舟子骂了柴静伪科学,罗永浩便和方舟子结下了梁子。

利用打桩机制定位内存泄漏

Linux 连接器支持一个很强大的技术,称为 库打桩(library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以追踪对某个特殊库函数的调用次数,验证或追踪它的输入输出值,或者甚至把它替换成一个完全不同的实现。以下使用打桩机制来检测 C 程序是否存在内存泄漏。

排查线上程序出现了CPU或内存高占用的原因

Linux 下可以通过 top 命令查看系统的健康状态,按下「1」来打开 CPU 列表,然后「shift + p」 以CPU 排序。查到 cpu 占用高的进程的 pid,然后看 CPU 主要消耗在用户态(us)还是内核态(sy)。用户态的函数跟踪用 ltrace , 内核态的函数跟踪用 strace 命令。以内核态为例:

1
2
sudo strace -p [pid] # 跟踪进程号为 pid 的进程的系统调用
sudo strace -cp [pid] # 上一个命令敲下来,可能跑了满屏的数据不便观察。-c选项汇总各个操作占用的时间

孤儿进程造成的进退维谷

如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些成为孤儿的进程在退出时将永远处于僵死状态,白白耗费内存。对于这个问题解决方法是给子进程在当前线程内找一个线程作为父亲,如果不行,就让init做它们的父亲。在do_exit() 中会调用exit_notify(),该函数会调用forget_original_parent(),而后调用 find_new_reaper()来执行寻父过程。

p.s. 在每个task_struct中都有一个parent指针,指向父进程task_struct。还有包含一个children的子进程链表。进程退出时,大部分清理工作都通过do_exit()(定义在/kernel/exit.c)来完成。 find_new_reaper中找到合适的养父进程后,只需要遍历children链表并为链表中每一个task_struct设置新的父进程(parent指针)即可。

1
2
3
4
5
6
7
8
9
reaper = find_new_reaper(father);
list_for_each_entry_safe(p, n, &father->children, sibling) {
p->real_parent = reaper;
if (p->parent == father) {
BUG_ON(p->ptrace);
p->parent = p->real_parent;
}
reparent_thread(p, father);
}