Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
Linux内存简介
由于BIOS
和Kernel
启动过程消耗了部分物理内存,因此MemTotal
值( free
命令获取)小于RAM
容量。
Linux
内存查询方式:
-
free
命令 /proc/meminfo
通过查询到的内存数据可以得到Linux
内存计算公式如下:
Code Block | ||
---|---|---|
| ||
total = used + free + buff/cache // 总内存 = 已使用内存 + 空闲内存 + 缓存 |
其中,已使用内存数据包括Kernel
消耗的内存和所有进程消耗的内存。
进程内存
进程消耗的内存包括:
- 虚拟地址空间映射的物理内存。
- 读写磁盘生成
PageCache
消耗的内存。
虚拟地址映射的物理内存
- 物理内存:硬件安装的内存(内存条)。
- 虚拟内存:操作系统为程序运行提供的内存。程序运行空间包括用户空间(用户态)和内核空间(内核态)。
- 用户态:低特权运行程序。
数据存储空间包括:
- 栈(
Stack
):函数调用的函数栈。 MMap(Memory Mapping Segment)
:内存映射区。- 堆(
Heap
):动态分配内存。 BBS
区:未初始化的静态变量存放区。Data
区:已初始化的静态常量存放区。Text
区:二进制可执行代码存放区。
用户态中运行的程序通过
MMap
将虚拟地址映射至物理内存中。 - 栈(
- 内核态:运行的程序需要访问操作系统内核数据。
数据存储空间包括:- 直接映射区:通过简单映射将虚拟地址映射至物理内存中。
VMALLOC
:内核动态映射空间,用于将连续的虚拟地址映射至不连续的物理内存中。- 持久内核映射区:将虚拟地址映射至物理内存的高端内存中。
- 固定映射区:用于满足特殊映射需求。
- 用户态:低特权运行程序。
虚拟地址映射的物理内存可以区分为共享物理内存和独占物理内存。如下图所示,物理内存1和3由进程A独占,物理内存2由进程B独占,物理内存4由进程A和进程B共享。
PageCache
除了通过MMap
文件直接映射外,进程文件还可以通过系统调用Buffered I/O
相关的Syscall
将数据写入到PageCache
,因此,PageCache
也会占用一部分内存。
进程内存统计指标
单进程内存统计指标
进程资源存储类型如下:
Anonymous
(匿名页):程序自行使用的堆栈空间,在磁盘上没有对应文件。File-backed
(文件页):资源存放在磁盘文件中,文件内包含代码段、字体信息等内容。
相关内存:
anno_rss(RSan)
:所有类型资源的独占内存。file_rss(RSfd)
:File-backed
资源占用的所有内存。shmem_rss(RSsh)
:Anonymous
资源的共享内存。
内存查询命令如下:
命令 | 内存 | 说明 | 计算公式 |
---|---|---|---|
| VIRT | 虚拟地址空间。 | 无 |
RES | RSS 映射的物理内存。 | anno_rss + file_rss + shmem_rss | |
SHR | 共享内存。 | file_rss + shmem_rss | |
MEM% | 内存使用率。 | RES / MemTotal | |
| VSZ | 虚拟地址空间。 | 无 |
RSS | RSS 映射的物理内存。 | anno_rss + file_rss + shmem_rss | |
MEM% | 内存使用率。 | RSS / MemTotal | |
| USS | 独占内存。 | anno_rss |
PSS | 按比例分配内存。 | anno_rss + file_rss/m + shmem_rss/n | |
RSS | RSS映射的物理内存。 | anno_rss + file_rss + shmem_rss |
Tip |
---|
|
cgroup
内存统计指标
cgroup
用于对Linux
的一组进程资源进行限制、管理和隔离。更多信息,请参见官方文档。cgroup
按层级管理,每个节点都包含一组文件,用于统计由这个节点包含的cgroup
的某些方面的指标。例如,Memory Control Group(memcg)
统计内存相关指标。
memory cgroup
文件包含以下指标:
Code Block | ||
---|---|---|
| ||
cgroup.event_control # 用于eventfd的接口 memory.usage_in_bytes # 显示当前已用的内存 memory.limit_in_bytes # 设置/显示当前限制的内存额度 memory.failcnt # 显示内存使用量达到限制值的次数 memory.max_usage_in_bytes # 历史内存最大使用量 memory.soft_limit_in_bytes # 设置/显示当前限制的内存软额度 memory.stat # 显示当前cgroup的内存使用情况 memory.use_hierarchy # 设置/显示是否将子cgroup的内存使用情况统计到当前cgroup里面 memory.force_empty # 触发系统立即尽可能的回收当前cgroup中可以回收的内存 memory.pressure_level # 设置内存压力的通知事件,配合cgroup.event_control一起使用 memory.swappiness # 设置和显示当前的swappiness memory.move_charge_at_immigrate # 设置当进程移动到其他cgroup中时,它所占用的内存是否也随着移动过去 memory.oom_control # 设置/显示oom controls相关的配置 memory.numa_stat # 显示numa相关的内存 |
其中需要关注以下3
个指标:
memory.limit_in_bytes
:限制当前cgroup
可以使用的内存大小。对应k8s
、docker
下的memory limits
值。memory.usage_in_bytes
:当前cgroup
里所有进程实际使用的内存总和,约等于memory.stat
文件下的RSS+Cache
值。memory.stat
:当前cgroup
的内存统计详情。memory.stat文件字段 说明 cache
PageCache
缓存页大小。rss
cgroup
中所有进程的anno_rss
内存之和。mapped_file
cgroup
中所有进程的file_rss
和shmem_rss
内存之和。active_anon
活跃LRU( least-recently-used
,最近最少使用)列表中所有Anonymous
进程使用内存和Swap
缓存,包括tmpfs
(shmem
),单位为bytes
。inactive_anon
不活跃 LRU
列表中所有Anonymous
进程使用内存和Swap
缓存,包括tmpfs
(shmem
),单位为bytes
。active_file
活跃 LRU
列表中所有File-backed
进程使用内存,以bytes
为单位。inactive_file
不活跃 LRU
列表中所有File-backed
进程使用内存,以bytes
为单位。unevictable
无法再生的内存,以 bytes
为单位。以上指标中如果带有
total_
前缀则表示当前cgroup
及其下所有子孙cgroup
对应指标之和。例如total_rss
指标表示当前cgroup
及其下所有子孙cgroup
的RSS
指标之和。
总结
单进程和进程cgroup
指标区别:
cgroup
的RSS
指标只包含anno_rss
,对应单进程下的USS
指标,因此cgroup
的mapped_file+RSS
则对应单进程下的RSS
指标。- 单进程中
PageCache
需单独统计,cgroup
中memcg
文件统计的内存已包含PageCache
。
内存 | 单进程 | 进程cgroup(memcg) |
---|---|---|
RSS | anon_rss + file_rss + shmem_rss | anon_rss |
mapped_file | 无 | file_rss + shmem_rss |
cache | 无 | PageCache |
Docker和K8s中的内存统计
Docker
和K8S
中的内存统计即Linux memcg
进程统计,但两者内存使用率的定义不同。
docker stat命令
返回示例如下:
Image Added
- LIMIT对应控制组的memory.limit_in_bytes。
- MEM USAGE对应控制组的memory.usage_in_bytes - memory.stat[total_cache]。
Tip |
---|
|
kubectl top pod命令
kubectl top
命令通过Metric-server
和Heapster
获取Cadvisor
中working_set
的值,表示Pod
实例使用的内存大小(不包括Pause
容器)。Metrics-server
中Pod
内存获取原理如下,更多信息,请参见官方文档。
Code Block | ||
---|---|---|
| ||
func decodeMemory(target *resource.Quantity, memStats *stats.MemoryStats) error {
if memStats == nil || memStats.WorkingSetBytes == nil {
return fmt.Errorf("missing memory usage metric")
}
*target = *uint64Quantity(*memStats.WorkingSetBytes, 0)
target.Format = resource.BinarySI
return nil
} |
Cadvisor
内存workingset
算法如下,更多信息,请参见官方文档。
Code Block | ||
---|---|---|
| ||
func setMemoryStats(s *cgroups.Stats, ret *info.ContainerStats) {
ret.Memory.Usage = s.MemoryStats.Usage.Usage
ret.Memory.MaxUsage = s.MemoryStats.Usage.MaxUsage
ret.Memory.Failcnt = s.MemoryStats.Usage.Failcnt
if s.MemoryStats.UseHierarchy {
ret.Memory.Cache = s.MemoryStats.Stats["total_cache"]
ret.Memory.RSS = s.MemoryStats.Stats["total_rss"]
ret.Memory.Swap = s.MemoryStats.Stats["total_swap"]
ret.Memory.MappedFile = s.MemoryStats.Stats["total_mapped_file"]
} else {
ret.Memory.Cache = s.MemoryStats.Stats["cache"]
ret.Memory.RSS = s.MemoryStats.Stats["rss"]
ret.Memory.Swap = s.MemoryStats.Stats["swap"]
ret.Memory.MappedFile = s.MemoryStats.Stats["mapped_file"]
}
if v, ok := s.MemoryStats.Stats["pgfault"]; ok {
ret.Memory.ContainerData.Pgfault = v
ret.Memory.HierarchicalData.Pgfault = v
}
if v, ok := s.MemoryStats.Stats["pgmajfault"]; ok {
ret.Memory.ContainerData.Pgmajfault = v
ret.Memory.HierarchicalData.Pgmajfault = v
}
workingSet := ret.Memory.Usage
if v, ok := s.MemoryStats.Stats["total_inactive_file"]; ok {
if workingSet < v {
workingSet = 0
} else {
workingSet -= v
}
}
ret.Memory.WorkingSet = workingSet
} |
通过以上命令算法可以得出,kubectl top pod
命令查询到的Memory Usage = Memory WorkingSet = memory.usage_in_bytes - memory.stat[total_inactive_file]
。
总结
命令 | 生态 | Memory Usage计算方式 |
---|---|---|
docker stat | Docker | memory.usage_in_bytes - memory.stat[total_cache] |
kubectl top pod | K8s | memory.usage_in_bytes - memory.stat[total_inactive_file] |
如果使用top
、ps
命令查询内存,则进程控制组下的Memory Usage
指标需对top
、ps
命令查询到的指标进行以下计算:
进程组生态 | 计算公式 |
---|---|
Memcg | rss + cache(active cache + inactive cache) |
Docker | rss |
K8s | rss + active cache |
参考资料
- https://www.alibabacloud.com/help/zh/arms/application-monitoring/memory-metrics
- http://hustcat.github.io/memory-usage-in-process-and-cgroup
- https://www.51cto.com/article/692936.html
Panel | ||
---|---|---|
| ||
|