一、容器内存概述
容器本质上还是一个进程,是一个被隔离和限制的进程。因此容器内存和进程内存在表现形式上其实是一样的,这块主要涉及三部分内容:RSS,page cache和swap这三部分,容器基于memory Cgroup对内存进行限制,但是具体限制的什么呢?又有哪些参数可以对其进行控制呢?
二、容器进程被莫名kill掉
在linux中当一个进程使用malloc申请分配内存的时候,操作系统并不会立即给该进程分配真实的物理存,此时分配的其实是虚拟内存。因此进程是可以申请超过物理内存上限的内存。为啥要这么设计呢?因为空闲内存空间是不断变化的,有进程申请必然有进程归还,此时申请的时候不够,谁能保证下一个时刻还不够呢?因此才有这个overcommit机制。
但是当一个进程在不断向内存中写数据的时候,如果内存还是不够用,此时就会OOM,被操作系统kill掉,毕竟不能把数据写到别的进程的内存空间中去,也算是一种保护机制。
当然kill掉是容器的默认行为,具体的这个行为是可以通过参数设置的。
其中43fxxxxxx 是容器的id,也就是每个容器都可以对其进行控制
还有几个比较重要的参数
从文件名称也可以看出来分别是最大限制,和当前使用。
每个运行的容器下面都有这些文件,可以自定义合适的参数值。
三、容器与page cache
进程除了有自己独立的RSS内存,如果涉及到文件的读写,linux还会为进程分配page cache,什么是page cache呢,page cache是操作系统在读写磁盘上的文件的时候,操作系统为了提升性能会预加载一部分内容到空闲的内存中来,而这部分空闲的内存则称为page cache。
但是如果没有空闲内存,而进程由要申请新的内存,则会回收page cache。保证内存供进程使用。
而上面提到的memory.usage.in_bytes = RSS + page cache
因此在某些情况下,memory.usage.in_bytes 是大于memory_limit_in_bytes的,但是不用担心,因为page cache是自动回收的。
因此查看容器的真实的内存占用,查看memory.usage.in_bytes 是不准的,需要看:
page cache不属于传统的内存限制范畴,是操作系统用来缓存文件的,不属于用户,属于操作系统内核,每个容器都可以使用page cache。
红色的部分就是page cache。
在关注容器的内存占用的时候,主要关注RSS。
四、容器和swap
swap其实并不是一块内存空间,而是一块磁盘空间,不过操作系统有时会将这块磁盘空间当作内存使用而已。当内存写满的时候,操作系统可以将一部分不用的数据暂时存放到swap空间上,待需要的时候再从swap中加载进来。
那么当内存紧张的时候,操作系统是会选择先释放page cache呢还是先把冷数据放到swap中去呢?
这个可以针对每一个容器进行定制化,具体修改下面这个配置文件:
swappiness的取值范围在0到100之间,
- 值为100的时候, 释放Page Cache和写冷数据到swap是同等优先级的。
- 值为60,这是大多数Linux系统的缺省值,这时候Page Cache的释放优先级高于写冷数据到swap。
- 值为0的时候,会限制该容器中的进程使用swap空间,仅对该容器生效
容器级别的swappiness会覆盖操作系统级别的。
因此swap也不属于传统内存的限制范畴,每个容器都可以使用。
五、总结
memory cgroup 限制的是容器真正使用到的内存,对于swap和page cache 都是内核级别的,是由操作系统进行管理的,是所有进程共享的,是不能被memory cgroup所限制的。