wwqdrh

限制内存使用量的实验

超过限制就会触发oom

首先需要一个能够消耗指定内存大小的进程

本来想挂载tmpfs来消耗指定内存(详情在文末的tmpfs与共享内存),但是发现这个内存占用是属于shared,不能归属于某个进程,无法限制

使用c的maclloc调用,消耗指定大小内存

import sys
import re
import time

def print_help():
    print("""Usage: unit: MB""")

if __name__ == "__main__":
    if len(sys.argv) == 2:
        s = ' ' * (int(sys.argv[1]) * 1024 * 1024)
        print('size of s: {}'.format(sys.getsizeof(s)))
        time.sleep(10000)
    else:
        print_help()

在v1版本中,与oomkiller相关的有

  • memory.limit_in_bytes
  • memory.oom_control:是否killer,默认为0要kill,设置为1不kill

在cgroupv2中,测试oom killer只与memory.max有关,设置最大的内存用量, 单位是byte,支持自己带,比如10m,会自动转换为byte格式

ps -ef | grep [name]找到进程对应的pid,加入到控制组中

echo 24756 >> ctest/cgroup.procs

# 设置memory.max
echo 52428800 >> memory.max # 50*1024*1024

发现并没有kill掉那个100MB的进程,另外cgroup中memory.curren也是为0,没有数据,猜测是只有加入到cgroup之后再申请的内存才会记录,以及触发oom,因此修改脚本

import sys
import re
import time
import os

def print_help():
    print("""Usage: unit: MB""")

if __name__ == "__main__":
    print(os.getpid())
    if len(sys.argv) == 2:
        ms = int(sys.argv[1])
        s = ''
        for i in range(ms):
            s += ' ' * (1024 * 1024)
            print('size of s: {}'.format(sys.getsizeof(s)))
            time.sleep(2) # 100m需要200s申请完毕,给足实验时间
        time.sleep(100)
    else:
        print_help()

验证有效,但是内存增长,不知为何只是会被memory.max限制住,不会oomkiller

但是如果把max调很小,oomkiller又会生效

原因分析

Memory Cgroup 里都不会对内核的内存做限制(比如页表,slab 等)

应用程序在申请内存的时候,比如说,调用 malloc() 来申请 100MB 的内存大小,malloc() 返回成功了,这时候系统其实只是把 100MB 的虚拟地址空间分配给了进程,但是并没有把实际的物理内存页面分配给进程。

当进程对这块内存地址开始做真正读写操作的时候,系统才会把实际需要的物理内存分配给进程。而这个过程中,进程真正得到的物理内存,就是这个 RSS

容器如果有部分内存是 Page Cache,如果进程需要申请新内存,page cache是可以被释放的。

可以在运行时查看memory.stat进行分析

anon 10289152 # 匿名映射中使用的内存量 brk()、sbrk() 和 mmap
file 0 # 用于缓存文件系统数据的内存量,包括 tmpfs 和共享内存。
kernel_stack 0 # 分配给内核堆栈的内存量
pagetables 65536 
percpu 0
sock 0
shmem 0
file_mapped 0
file_dirty 0
file_writeback 0
swapcached 110592 # 交换缓存量
anon_thp 0
file_thp 0
shmem_thp 0
inactive_anon 10391552 # 页回收算法使用的内部内存管理列表上的内存量
active_anon 8192
inactive_file 0
active_file 0
unevictable 0
slab_reclaimable 0
slab_unreclaimable 288
slab 288
workingset_refault_anon 28
workingset_refault_file 0
workingset_activate_anon 2
workingset_activate_file 0
workingset_restore_anon 0
workingset_restore_file 0
workingset_nodereclaim 0
pgfault 44105
pgmajfault 27
pgrefill 47
pgscan 78593
pgsteal 21000
pgactivate 1237
pgdeactivate 47
pglazyfree 0
pglazyfreed 0
thp_fault_alloc 0
thp_collapse_alloc 0

所以cgroup对于内存的限制并不能严格控制

但是对于这个python程序,实际查看过占用的RSS就是指定的大小,但是不知为何却是无法kill,后面有空再分析吧

参考

tmpfs与共享内存

创建虚拟内存文件系统,不断写入数据达到消耗内存的目的,需要清除内存时,删除创建的虚拟内存目录即可

#!/bin/bash

FILE_NAME=`basename $0`
memsize=$2

function usage()
{
    echo "Usage:$FILE_NAME consume memory_size|release -----the value of memory_size like 100M 2G and etc"
    echo "Example: $FILE_NAME consume 1G"
    echo " $FILE_NAME release"
}

function consume()
{
    if [ -d /tmp/memory ];then
        echo "/tmp/memory already exists"
    else
        mkdir /tmp/memory
    fi

    mount -t tmpfs -o size=$1 tmpfs /tmp/memory
    dd if=/dev/zero of=/tmp/memory/block
}

function release()
{
    rm /tmp/memory/block;ret=$?
    if [ $ret != 0 ]; then
        echo "remove memory data failed"
        return $ret
    fi

    umount /tmp/memory;ret=$?
    if [ $ret != 0 ]; then
        echo "umount memory filedir failed"
        return $ret
    fi

    rmdir /tmp/memory;ret=$?
    if [ $ret != 0 ]; then
        echo "remove memory filedir failed"
        return $ret
    fi
}

function main()
{
    case "$1" in
        consume) consume $memsize;;
        release) release;;
        *) usage;exit 1;;
    esac
}

main $*