此文件包含有关在 Zircon 中进行内存管理和诊断的信息, 并讨论了检查进程和系统内存使用情况的方法。
进程可以通过以下 3 种方式使用内存:
- 以堆、线程堆栈、可执行代码 + 数据的形式映射的内存。 此内存由 VMAR 表示 而后者存储的是对 VMO 的引用。 程序员通常通过内存地址与该内存交互。
- 独立 VMO。这些是不通过 VMAR。编程人员通过句柄与该内存进行交互;通常会发出 vmo_read 和 vmo_write。
- 以内核对象句柄的形式表示的内核内存。
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 版本,则可以使用树状图直观呈现内存使用情况, 系统。
在主机上,从命令行 Fuchsia 结账:
./scripts/fx shell memgraph -vt | ./scripts/memory/treemap.py > mem.html
在浏览器中打开
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>
r
:ZX_RIGHT_READ
w
:ZX_RIGHT_WRITE
x
:ZX_RIGHT_EXECUTE
m
:ZX_RIGHT_MAP
d
:ZX_RIGHT_DUPLICATE
t
:ZX_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
转储的输出。
限制
ps
和vmaps
目前均未计入:
- 未映射的 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
...