Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Linux内存简介

由于BIOS和Kernel启动过程消耗了部分内存,因此MemTotal值(free命令获取)小于RAM容量。
dmesg | grep Memory
Memory: 131604168K/134217136K available (14346K kernel code, 9546K rwdata, 9084K rodata, 2660K init, 7556K bss, 2612708K reserved, 0K cma-reserved)

Linux内存查询命令:

free命令

/proc/meminfo命令

通过查询到的内存数据可以得到Linux内存计算公式如下:

由于BIOSKernel启动过程消耗了部分物理内存,因此MemTotal值( free 命令获取)小于RAM容量。 Linux内存查询方式:

  • free 命令
  • /proc/meminfo

通过查询到的内存数据可以得到Linux内存计算公式如下:

Code Block
languagebash
# 总内存 = 已使用内存 + 空闲内存 + 缓存
total = used + free + buff/cache 
//总内存=已使用内存+空闲内存+缓存

其中,已使用内存数据包括Kernel消耗的内存和所有进程消耗的内存。

其中,已使用内存数据包括Kernel消耗的内存和所有进程消耗的内存。
说明
kernel used=Slab + VmallocUsed + PageTables + KernelStack + HardwareCorrupted + Bounce + X

进程内存

进程消耗的内存包括:

  • 虚拟地址空间映射的物理内存。读写磁盘生成PageCache消耗的内存。
  • 读写磁盘生成PageCache消耗的内存。

虚拟地址映射的物理内存

Image Added

  • 物理内存:硬件安装的内存(内存条)。
  • 虚拟内存:操作系统为程序运行提供的内存。程序运行空间包括用户空间(用户态)内核空间(内核态)
    • 用户态:低特权运行程序。数据存储空间包括:
      • 栈(Stack):函数调用的函数栈。
      • MMap(Memory Mapping Segment):内存映射区。
      • 堆(Heap):动态分配内存。
      • BBS区:未初始化的静态变量存放区。
      • Data区:已初始化的静态常量存放区。
      • Text区:二进制可执行代码存放区。

      用户态中运行的程序通过MMap将虚拟地址映射至物理内存中。

    • 内核态:运行的程序需要访问操作系统内核数据。数据存储空间包括:
      • 直接映射区:通过简单映射将虚拟地址映射至物理内存中。
      • VMALLOC:内核动态映射空间,用于将连续的虚拟地址映射至不连续的物理内存中。
  • 物理内存:硬件安装的内存(内存条)。
  • 虚拟内存:操作系统为程序运行提供的内存。程序运行空间包括用户空间(用户态)和内核空间(内核态)。虚拟内存分区Image Removed
    • 用户态:低特权运行程序。

      数据存储空间包括:

      • 栈(Stack):函数调用的函数栈
      • MMap(Memory Mapping Segment):内存映射区
      • 堆(Heap):动态分配内存
      • BBS区:未初始化的静态变量存放区
      • Data区:已初始化的静态常量存放区
      • Text区:二进制可执行代码存放区

      用户态中运行的程序通过MMap将虚拟地址映射至物理内存中。

    • 内核态:运行的程序需要访问操作系统内核数据。
      数据存储空间包括:
      • 直接映射区:通过简单映射将虚拟地址映射至物理内存中。
      • VMALLOC:内核动态映射空间,用于将连续的虚拟地址映射至不连续的物理内存中。
      • 持久内核映射区:将虚拟地址映射至物理内存的高端内存中。
      • 固定映射区:用于满足特殊映射需求。

虚拟地址映射的物理内存可以区分为共享物理内存独占物理内存。如下图所示,物理内存1和3由进程A独占,物理内存2由进程B独占,物理内存4由进程A和进程B共享。

Image Added虚拟地址映射的物理内存可以区分为共享物理内存和独占物理内存。如下图所示,物理内存1和3由进程A独占,物理内存2由进程B独占,物理内存4由进程A和进程B共享。内存映射表Image Removed

PageCache

除了通过MMap文件直接映射外,进程文件还可以通过系统调用Buffered I/O相关的Syscall将数据写入到PageCache,因此,PageCache也会占用一部分内存。pagecacheImage Removed

除了通过MMap文件直接映射外,进程文件还可以通过系统调用Buffered I/O相关的Syscall将数据写入到PageCache,因此,PageCache也会占用一部分内存。

Image Added

进程内存统计指标

单进程内存统计指标

进程资源存储类型如下:

  • Anonymous(匿名页):程序自行使用的堆栈空间,在磁盘上没有对应文件。
  • File-backed(文件页):资源存放在磁盘文件中,文件内包含代码段、字体信息等内容。

说明
相关指标:进程资源有如下类型:

  • anno_
rss(RSan):所有类型资源的独占内存。
  • rss表示没有映射到文件的内存量,即匿名内存。匿名内存通常是进程通过malloc或类似的方法动态分配的内存。
  • file_
rss(RSfd):File-backed资源占用的所有内存。
  • shmem_rss(RSsh):Anonymous资源的共享内存。
    • rss:表示映射到文件的内存量。如果一个进程打开了一个文件并将其映射到内存,那么这部分内存就会被计入file_rss
    • shmem_rss:表示共享内存量。如果多个进程共享一部分内存,那么这部分内存就会被计入shmem_rss
    Tip

    RSS( resident set size):驻留集大小。表示进程已装入内存的页面的集合。

    常用内存查询命令

    top

    Tip

    该命令展示的内存单位默认为KB

    Image Added

    命令内存

    指标查询命令如下:

    命令查询指标
    说明计算公式



    top

    VIRT(Virtual Set Size)虚拟地址空间。
    RES
    RSS映射的物理内存。
    (Resident Set Size)RSS映射的物理内存。anno_rss + file_rss + shmem_rss
    SHR(Shared Memory)共享内存。file_rss + shmem_rss
    MEM%
    %MEM内存使用率。RES / MemTotal

    ps

    Tip

    该命令展示的内存单位默认为KB

    Image Added

    命令内存说明计算公式

    ps

    VSZ(Virtual Set Size)虚拟地址空间。
    RSS
    RSS映射的物理内存。
    (Resident Set Size)RSS映射的物理内存。anno_rss + file_rss + shmem_rss
    MEM%
    %MEM内存使用率。RSS / MemTotal

    smem

    Tip

    该命令需要单独安装。

    Image Added

    命令内存说明计算公式


    smem

    USS(Unique Set Size)独占内存。anno_rss
    PSS(Proportional Set Size)按比例分配内存。anno_rss + file_rss/m + shmem_rss/n
    RSS
    RSS映射的物理内存。
    (Resident Set Size)RSS映射的物理内存。anno_rss + file_rss + shmem_rss

    内存指标关系

    内存指标含义Image RemovedImage Added说明

    Tip
    WSS(Memoy

    WSS(Memoy Working Set

    Size)指标:一种更为合理评估进程内存真实使用内存的计算方式。但是受限于Linux Page Reclaim机制,这个概念目前还只是概念,并没有哪一个工具可以正确统计出WSS,只能是趋近。

    Size)指标:一种更为合理评估进程内存真实使用内存的计算方式。但是受限于Linux Page Reclaim机制,这个概念目前还只是概念,并没有哪一个工具可以正确统计出WSS,只能是趋近。

    cgroup内存统计指标

    cgroup用于对Linux的一组进程资源进行限制、管理和隔离。更多信息,请参见

    进程控制组内存统计指标

    控制组(Cgroup)用于对Linux的一组进程资源进行限制、管理和隔离。更多信息,请参见官方文档
    Cgroup按层级管理,每个节点都包含一组文件,用于统计由这个节点包含的控制组的某些方面的指标。例如,Memory Control Group(memcg)统计内存相关指标。cgroup架构Image Removed

    Memory Cgroup文件包含以下指标:

    cgroup按层级管理,每个节点都包含一组文件,用于统计由这个节点包含的cgroup的某些方面的指标。例如,Memory Control Group(memcg)统计内存相关指标。 
    Image Added

    memory cgroup文件包含以下指标:

    Code Block
    languagebash
    cgroup.event_control       # 
    #用于eventfd的接口
    用于eventfd的接口
    memory.usage_in_bytes      
    #显示当前已用的内存
    # 显示当前已用的内存
    memory.limit_in_bytes      # 
    #设置
    设置/显示当前限制的内存额度
    memory.failcnt             # 
    #显示内存使用量达到限制值的次数
    显示内存使用量达到限制值的次数
    memory.max_usage_in_bytes  # 
    #历史内存最大使用量
    历史内存最大使用量
    memory.soft_limit_in_bytes # 
    #设置
    设置/显示当前限制的内存软额度
    memory.stat                # 
    #显示当前cgroup的内存使用情况
    显示当前cgroup的内存使用情况
    memory.use_hierarchy       
    #设置
    # 设置/显示是否将子cgroup的内存使用情况统计到当前cgroup里面
    memory.force_empty         # 
    #触发系统立即尽可能的回收当前cgroup中可以回收的内存
    触发系统立即尽可能的回收当前cgroup中可以回收的内存
    memory.pressure_level      
    #设置内存压力的通知事件,配合cgroup
    # 设置内存压力的通知事件,配合cgroup.event_control一起使用
    memory.swappiness          # 
    #设置和显示当前的swappiness
    设置和显示当前的swappiness
    memory.move_charge_at_immigrate # 
    #设置当进程移动到其他cgroup中时,它所占用的内存是否也随着移动过去
    设置当进程移动到其他cgroup中时,它所占用的内存是否也随着移动过去
    memory.oom_control         # 
    #设置
    设置/显示oom controls相关的配置
    memory.numa_stat           
    #显示numa相关的内存
    # 显示numa相关的内存

    其中需要关注以下3个指标:

    其中需要关注以下3个指标:

    • memory.limit_in_bytes:限制当前控制组可以使用的内存大小。对应K8s、Docker下memory limit指标。bytes:限制当前cgroup可以使用的内存大小。对应k8sdocker下的memory limits值。
    • memory.usage_in_bytes:当前控制组里所有进程实际使用的内存总和,约等于memory.stat文件下的RSS+Cache指标值。bytes:当前cgroup里所有进程实际使用的内存总和,约等于memory.stat文件下的RSS+Cache值。
    • memory.stat:当前控制组的内存统计详情。stat:当前cgroup的内存统计详情。
      memory.stat文件字段说明
      cache
      PageCache缓存页大小。
      PageCache缓存页大小。
      rss
      控制组中所有进程的anno_rss内存之和。
      cgroup中所有进程的anno_rss内存之和。
      mapped_file
      控制组中所有进程的file_rss和shmem_rss内存之和。
      cgroup中所有进程的file_rssshmem_rss内存之和。
      active_anon
      活跃LRU(least
      活跃LRU(least-recently-
      used,最近最少使用)列表中所有Anonymous进程使用内存和Swap缓存,包括
      used,最近最少使用)列表中所有Anonymous进程使用内存和Swap缓存,包括 tmpfsshmem
      ),单位为字节。
      ),单位为bytes
      inactive_anon
      不活跃LRU列表中所有Anonymous进程使用内存和Swap缓存,包括
      不活跃LRU列表中所有Anonymous进程使用内存和Swap缓存,包括 tmpfsshmem
      ),单位为字节。
      ),单位为bytes
      active_file
      活跃LRU列表中所有File-backed进程使用内存,以字节为单位。
      活跃LRU列表中所有File-backed进程使用内存,以bytes为单位。
      inactive_file
      不活跃LRU列表中所有File-backed进程使用内存,以字节为单位。
      不活跃LRU列表中所有File-backed进程使用内存,以bytes为单位。
      unevictable
      无法再生的内存,以字节为单位。
      无法再生的内存,以bytes为单位。

      以上指标中如果带有total_前缀则表示当前控制组及其下所有子孙控制组对应指标之和。例如前缀则表示当前cgroup及其下所有子孙cgroup对应指标之和。例如total_rss指标表示当前控制组及其下所有子孙控制组的RSS指标之和。指标表示当前cgroup及其下所有子孙cgroupRSS指标之和。

    总结

    单进程和进程控制组指标区别:

    单进程和进程cgroup指标区别:

    • cgroupRSS指标只包含anno_rss,对应单进程下的USS指标,因此cgroupmapped_file+RSS则对应单进程下的RSS指标。
    • 单进程中PageCache需单独统计,cgroup memcg 文件统计的内存已包含PageCache
    内存单进程进程cgroup(memcg)
    指标单进程进程控制组(memcg)
    RSSanon_rss + file_rss + shmem_rssanon_rss
    mapped_filefile_rss + shmem_rss
    cachePageCache
  • 控制组的RSS指标只包含anno_rss,对应单进程下的USS指标,因此控制组的mapped_file+RSS则对应单进程下的RSS指标。
  • Docker和K8s中的内存统计

    DockerK8S中的内存统计即Linux memcg进程统计,但两者内存使用率的定义不同。

    docker stat命令

    返回示例如下:

    Image Added

    • LIMIT对应控制组的memory.limit_in_bytes
    • MEM USAGE对应控制组的memory.usage_in_bytes - memory.stat[total_cache]
    Tip

    docker stat命令查询原理,请参见官方文档。 

    kubectl top pod命令

    kubectl top命令通过Metric-serverHeapster获取Cadvisorworking_set的值,表示Pod实例使用的内存大小(不包括Pause容器)。Metrics-serverPod内存获取原理如下,更多信息,请参见官方文档

    Code Block
    languagego
    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
    languagego
    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 statdockermemory.usage_in_bytes - memory.stat[total_cache]
    kubectl top podk8smemory.usage_in_bytes - memory.stat[total_inactive_file]


    如果使用top/ps命令查询内存,则cgroup下的Memory Usage指标需对top/ps命令查询到的指标进行以下计算:

    进程组生态计算公式
    cgrouprss + cache(active cache + inactive cache)
    dockerrss
    k8srss + active cache

    参考资料

    单进程中PageCache需单独统计,控制组中memcg文件统计的内存已包含PageCache。




    Panel
    titleContent Menu

    Table of Contents