eventfd
eventfd包含一个由内核维护的64位无符号整型计数器,创建eventfd时会返回一个文件描述符,进程可以通过对这个文件描述符进行read/write来读取/改变计数器的值
用途
- 线程或者父子进程间通信,是一种事件通知方式
- 内核通过eventfd也可以向用户空间进程发消息,cgroup就是通过这种方式通知的
当write 的时候计数器会累加
#include <sys/eventfd.h>
//initval:初始值
//EFD_CLOEXEC : close-on-exec
//EFD_NONBLOCK : non block
//EFD_SEMAPHORE : 信号量 ,读操作只是减1, 如果不是信号量的话,则读出count的值,计数器清0
int eventfd(unsigned int initval, int flags);
cgroup
用来限制内核内存就是限制当前cgroup所能使用的内核资源
需要kernel的支持
CONFIG_MEMCG=y
CONFIG_MEMCG_KMEM=y
#define MEMCG_SYSFS_PATH "/dev/memcg/"
#define MEMPRESSURE_WATCH_LEVEL "medium"
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY);
if (mpfd < 0) {
ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
goto err_open_mpfd;
}
evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY);
if (evctlfd < 0) {
ALOGI("No kernel memory cgroup event control (errno=%d)", errno);
goto err_open_evctlfd;
}
evfd = eventfd(0, EFD_NONBLOCK);
if (evfd < 0) {
ALOGE("eventfd failed for level %s; errno=%d", levelstr, errno);
goto err_eventfd;
}
//写入这种格式,会读到内核OOM事件
ret = snprintf(buf, sizeof(buf), "%d %d %s", evfd, mpfd, levelstr);
if (ret >= (ssize_t)sizeof(buf)) {
ALOGE("cgroup.event_control line overflow for level %s", levelstr);
goto err;
}
ret = write(evctlfd, buf, strlen(buf) + 1);
lowmemorykiller
- 如果use_inkernel_interface=1
则并不使用cgroup机制,是低版本内核中处理lowmemorykill - 使用cgroup机制,在用户态处理lowmemorykill。
内核处理
lowmem_scan
当触发lmkd,则先杀oom_score_adj最大的进程, 当oom_adj相等时,则选择rss最大的进程。
static struct shrinker lowmem_shrinker = {
.scan_objects = lowmem_scan,
.count_objects = lowmem_count,
.seeks = DEFAULT_SEEKS * 16
};
static int __init lowmem_init(void) {
register_shrinker(&lowmem_shrinker);
return 0;
}
static void __exit lowmem_exit(void) {
unregister_shrinker(&lowmem_shrinker);
}
static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
...
//发送singal kill -9
send_sig(SIGKILL, selected, 0);
...
}
module_init(lowmem_init);
module_exit(lowmem_exit);
和用户态的接口
/sys/module/lowmemorykiller/parameters/minfree
/sys/module/lowmemorykiller/parameters/adj //adj就是oom_score_adj: 取值范围[-1000, 1000]
//oom_adj:代表进程的优先级, 数值越大,优先级越低,越容易被杀. 取值范围[-16, 15]
#cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,36864,46080
#cat /sys/module/lowmemorykiller/parameters/adj
0,58,117,176,529,1000
#cat /proc/138/oom_adj
-17
#cat /proc/138/oom_score
0
当系统可用内存低于36864个pages时,则会杀掉oom_score_adj>=529的进程
当系统可用内存低于32256个pages时,则会杀掉oom_score_adj>=176的进程
…