内存使用量

此文件包含有关在 Zircon 中进行内存管理和诊断的信息, 并讨论了检查进程和系统内存使用情况的方法。

进程可以通过以下 3 种方式使用内存:

  1. 以堆、线程堆栈、可执行代码 + 数据的形式映射的内存。 此内存由 VMAR 表示 而后者存储的是对 VMO 的引用。 程序员通常通过内存地址与该内存交互。
  2. 独立 VMO。这些是不通过 VMAR。编程人员通过句柄与该内存进行交互;通常会发出 vmo_readvmo_write
  3. 以内核对象句柄的形式表示的内核内存。

Fuchsia 遵循过度使用模型:进程分配的内存比 可以在特定时刻满足,并且随着内存页面写入, 由内核即时进行物理分配(有线)。

用户空间内存

哪些进程占用了全部内存?

转储进程的总内存用量

使用 ps 工具:

$ ps
TASK           PSS PRIVATE  SHARED NAME
j:1028       32.9M   32.8M         root
  p:1043   1386.3k   1384k     28k bin/devmgr
  j:1082     30.0M   30.0M         zircon-drivers
    p:1209  774.3k    772k     28k /boot/bin/acpisvc
    p:1565  250.3k    248k     28k driver_host
    p:1619  654.3k    652k     28k driver_host
    p:1688  258.3k    256k     28k driver_host
    p:1867 3878.3k   3876k     28k driver_host
    p:1916   24.4M   24.4M     28k driver_host
  j:1103   1475.7k   1464k         zircon-services
    p:1104  298.3k    296k     28k crashlogger
    p:1290  242.3k    240k     28k netsvc
    p:2115  362.3k    360k     28k sh:console
    p:2334  266.3k    264k     28k sh:vc
    p:2441  306.3k    304k     28k /boot/bin/ps
TASK           PSS PRIVATE  SHARED NAME

PSS(按比例共享状态)是字节数,用于估算 进程使用的进程内映射物理内存。其值为 PRIVATE + (SHARED / sharing-ratio),其中 sharing-ratio 取决于 这些进程共享了该进程中的每一个页面。

其意图是,例如,如果四个进程共享一个页面,则 1/4 的 该页面的字节包含在四个进程的 PSS 中。如果两个 每个进程共享不同的页面,则每个进程会获得该页面的 1/2 字节。

PRIVATE 是仅由此进程映射的字节数。例如, 没有其他进程映射此内存。请注意,这未考虑私享视频 未映射的 VMO。

SHARED 是此进程映射的字节数,至少 另一个进程请注意,这不考虑非共享 VMO 映射。它也不表示有多少个进程共享该内存: 可以是 2,也可以是 50。

直观呈现内存用量

如果您有 Fuchsia 版本,则可以使用树状图直观呈现内存使用情况, 系统。

  1. 在主机上,从命令行 Fuchsia 结账:

    ./scripts/fx shell memgraph -vt | ./scripts/memory/treemap.py > mem.html

  2. 在浏览器中打开 mem.html

memgraph 工具生成系统任务和内存的 JSON 描述 信息,随后由 treemap.py 脚本进行解析。-vt说 在输出中包含 VMO 和线程。

转储进程的详细内存映射

如果您想了解为什么某个特定进程使用如此大的内存,您可以运行 vmaps 工具(koid 是运行 ps 时显示的 ID)来查看 映射到内存中的内容

$ vmaps help
Usage: vmaps <process-koid>

Dumps a process's memory maps to stdout.

First column:
  "/A" -- Process address space
  "/R" -- Root VMAR
  "R"  -- VMAR (R for Region)
  "M"  -- Mapping

  Indentation indicates parent/child relationship.

列标记:

  • :sz:条目的虚拟大小(以字节为单位)。并非所有网页 必须由物理内存提供支持
  • :res:“常驻”内存量(以字节为单位);即 为条目提供支持的物理内存量。此回忆可能是不公开的 (只能由此进程访问)或由多个进程共享。
  • :vmo:映射到此区域的 VMO 的 koid
$ vmaps 2470
/A ________01000000-00007ffffffff000    128.0T:sz                    'proc:2470'
/R ________01000000-00007ffffffff000    128.0T:sz                    'root'
...
# This 'R' region is a dynamic library. The r-x section is .text, the r--
# section is .rodata, and the rw- section is .data + .bss.
R  00000187bc867000-00000187bc881000      104k:sz                    'useralloc'
 M 00000187bc867000-00000187bc87d000 r-x   88k:sz   0B:res  2535:vmo 'libfdio.so'
 M 00000187bc87e000-00000187bc87f000 r--    4k:sz   4k:res  2537:vmo 'libfdio.so'
 M 00000187bc87f000-00000187bc881000 rw-    8k:sz   8k:res  2537:vmo 'libfdio.so'
...
# This 2MB anonymous mapping is probably part of the heap.
M  0000246812b91000-0000246812d91000 rw-    2M:sz  76k:res  2542:vmo 'mmap-anonymous'
...
# This region looks like a stack: a big chunk of virtual space (:sz) with a
# slightly-smaller mapping inside (accounting for a 4k guard page), and only a
# small amount actually committed (:res).
R  0000358923d92000-0000358923dd3000      260k:sz                    'useralloc'
 M 0000358923d93000-0000358923dd3000 rw-  256k:sz  16k:res  2538:vmo ''
...
# The stack for the initial thread, which is allocated differently.
M  0000400cbba84000-0000400cbbac4000 rw-  256k:sz   4k:res  2513:vmo 'initial-stack'
...
# The vDSO, which only has .text and .rodata.
R  000047e1ab874000-000047e1ab87b000       28k:sz                    'useralloc'
 M 000047e1ab874000-000047e1ab87a000 r--   24k:sz  24k:res  1031:vmo 'vdso/stable'
 M 000047e1ab87a000-000047e1ab87b000 r-x    4k:sz   4k:res  1031:vmo 'vdso/stable'
...
# The main binary for this process.
R  000059f5c7068000-000059f5c708d000      148k:sz                    'useralloc'
 M 000059f5c7068000-000059f5c7088000 r-x  128k:sz   0B:res  2476:vmo '/boot/bin/sh'
 M 000059f5c7089000-000059f5c708b000 r--    8k:sz   8k:res  2517:vmo '/boot/bin/sh'
 M 000059f5c708b000-000059f5c708d000 rw-    8k:sz   8k:res  2517:vmo '/boot/bin/sh'
...

您还可以使用 aspace 命令来显示内存映射, zxdb

转储与进程关联的所有 VMO

vmos <pid>

这还会显示未映射的 VMO,其目前既不是 ps,也不是 vmaps

它还显示某个 VMO 是否是一个子项,以及其父项的 Kid。

$ vmos 1118
rights  koid parent #chld #map #shr    size   alloc name
rwxmdt  1170      -     0    1    1      4k      4k stack: msg of 0x5a
r-xmdt  1031      -     2   28   14     28k     28k vdso/stable
     -  1298      -     0    1    1      2M     68k jemalloc-heap
     -  1381      -     0    3    1    516k      8k self-dump-thread:0x12afe79c8b38
     -  1233   1232     1    1    1   33.6k      4k libbacktrace.so
     -  1237   1233     0    1    1      4k      4k data:libbacktrace.so
...
     -  1153   1146     1    1    1  883.2k     12k ld.so.1
     -  1158   1153     0    1    1     16k     12k data:ld.so.1
     -  1159      -     0    1    1     12k     12k bss:ld.so.1
rights  koid parent #chld #map #shr    size   alloc name

列数:

  • rights:如果进程通过句柄指向 VMO,此列会显示 标识名所拥有的权利,零个或多个: <ph type="x-smartling-placeholder">
      </ph>
    • rZX_RIGHT_READ
    • wZX_RIGHT_WRITE
    • xZX_RIGHT_EXECUTE
    • mZX_RIGHT_MAP
    • dZX_RIGHT_DUPLICATE
    • tZX_RIGHT_TRANSFER
    • 注意:非标识名条目将带有一个“-”。
  • koid:VMO 的 Kid(如果有)。否则为零。没有 koid 由内核创建,从未有过用户空间句柄。
  • parent:VMO 的父级的 koid(如果是一个子级)。
  • #chld:VMO 的活跃子项数量。
  • #map:VMO 当前映射到 VMAR 的次数。
  • #shr:映射(共享)VMO 的进程数量。
  • size:VMO 的当前大小(以字节为单位)。
  • alloc:分配给 VMO 的物理内存量(以字节为单位)。
    • 注意:如果此列包含值 phys,则表示 VMO 指向原始物理地址范围,就像内存映射设备一样。 phys VMO 不会消耗 RAM。
  • name:VMO 的名称;如果名称为空,则为 -

将其与 ps 联系起来:每个 VMO 都计入其映射部分 (因为不是 VMO 的所有或任何页面都可以映射):

PRIVATE =  #shr == 1 ? alloc : 0
SHARED  =  #shr  > 1 ? alloc : 0
PSS     =  PRIVATE + (SHARED / #shr)

您还可以使用 handle 命令来显示 VMO 信息 zxdb

转储“已隐藏”(未映射的内核)VMO

k zx vmos hidden

vmos <pid> 类似,但会转储系统中未映射的所有 VMO 进入任何进程:

  • 用户空间具有句柄但不映射的 VMO
  • 仅映射到内核空间的 VMO
  • 仅限内核、未映射且没有句柄的 VMO

koid 值为零表示只有内核具有对该 VMO 的引用。

#map 值为零表示 VMO 未映射到任何地址空间。

另请参阅k zx vmos all,用于转储系统中的所有 VMO。注意: 此输出因内核控制台而被截断很常见。 缓冲区限制,因此通常最好将 k zx vmos hidden 包含每个用户进程的 vmaps 转储的输出。

限制

psvmaps目前均未计入:

  • 未映射的 VMO 或 VMO 子范围。例如,您可以创建一个 VMO, 其中就有 1G 的数据,这些数据就不会在这里显示。

所有进程转储工具都不会考虑:

  • 叠加映射的网页。如果您使用同一范围创建多个映射 因此该 VMO 的任何已提交页面都将被计为 系统会映射这些网页可以在同一个进程内,也可以 (如果这些进程共享一个 VMO)。

    请注意,“叠加映射的网页”包含写入时复制

  • 由进程分配的资源的底层内核内存开销。 例如,一个进程可能会打开 100 万个句柄,这些句柄会耗用 内核内存。

    您可以使用 k zx ps 命令查看进程句柄的耗用情况;跑步 使用 k zx ps help 获取有关其列的说明。

  • 写入时复制 (COW) 克隆的 VMO。网页的干净(非脏、未复制)网页 克隆将不会计入“已共享”用于映射克隆的进程 并且这些页面可能会被错误地计为“不公开”某个进程 映射父级(克隆)VMO。

    TODO(dbort):修复此问题;这些工具是在 COW 克隆出现之前编写的。

内核内存

转储系统内存领域和内核堆使用情况

运行 kstats -m 将持续转储有关物理内存的信息 使用情况和可用性。

$ kstats -m
--- 2017-06-07T05:51:08.021Z ---
mem total      free      VMOs     kheap     kfree     wired       mmu       ipc     other
    2048M   1686.4M    317.8M      5.1M      0.9M     17.8M     20.0M      0.1M      0.0M

--- 2017-06-07T05:51:09.021Z ---
...

字段:

  • -t 选项会显示时间戳 2017-06-07T05:51:08.021Z, (ISO 8601 字符串)
  • total:系统可用的物理内存总量。
  • free:未分配内存量。
  • VMOs:为 VMO(内核和用户)分配的内存量。答 所有用户空间内存的超集。不包括某些 低于 wired
  • kheap:标记为“已分配”的内核堆内存量。
  • kfree:标记为空闲的内核堆内存量。
  • wired:为以下对象的内核预留并映射到内核中的内存量 原因。通常用于只读 RAM 磁盘和内核映像等数据,以及前期启动动态内存的相关数据。
  • mmu:特定于架构的 MMU 元数据(如 页面表格。
  • ipc:进程间通信使用的内存量。
  • other:其余的 other

转储内核地址空间

k zx asd kernel

转储内核的 VMAR/映射/VMO 层次结构,类似于 vmaps 工具 用户进程

$ k zx asd kernel
as 0xffffffff80252b20 [0xffffff8000000000 0xffffffffffffffff] sz 0x8000000000 fl 0x1 ref 71 'kernel'
  vmar 0xffffffff802529a0 [0xffffff8000000000 0xffffffffffffffff] sz 0x8000000000 ref 1 'root'
    map 0xffffff80015f89a0 [0xffffff8000000000 0xffffff8fffffffff] sz 0x1000000000 mmufl 0x18 vmo 0xffffff80015f8890/k0 off 0 p ages 0 ref 1 ''
      vmo 0xffffff80015f8890/k0 size 0 pages 0 ref 1 parent k0
    map 0xffffff80015f8b30 [0xffffff9000000000 0xffffff9000000fff] sz 0x1000 mmufl 0x18 vmo 0xffffff80015f8a40/k0 off 0 pages 0 ref 1 ''
      object 0xffffff80015f8a40 base 0x7ffe2000 size 0x1000 ref 1
    map 0xffffff80015f8cc0 [0xffffff9000001000 0xffffff9000001fff] sz 0x1000 mmufl 0x1a vmo 0xffffff80015f8bd0/k0 off 0 pages 0 ref 1 ''
      object 0xffffff80015f8bd0 base 0xfed00000 size 0x1000 ref 1
...