記憶體用量

這個檔案包含 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 是以這個程序共用各頁面的程序數量為計算依據。

也就是說,假設有 4 個程序共用單一頁面,則這四個程序的 PSS 都會包含該網頁的 1/4 位元組。如果兩個程序共用不同的頁面,則每個程序會獲得該頁面的 1/2 位元組。

PRIVATE 是此程序僅對應的位元組數量。也就是說, 其他程序不會繪製這個記憶體請注意,系統不會將未對應的私人 VMO 列入計算。

SHARED 是這項程序和至少一個其他程序所對應的位元組數。請注意,這並未計入未對應的共用 VMO。也不會指出共用記憶體的處理程序數量:可能為 2 個,可以是 50 個。

視覺化呈現記憶體用量

如果您有 Fuchsia 版本,可以使用樹狀圖來呈現系統的記憶體用量。

  1. 在主體機器上,從 Fuuchsia 結帳功能的根目錄執行下列指令:

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

  2. 在瀏覽器中開啟 mem.html

memgraph 工具會產生系統工作和記憶體資訊的 JSON 說明,然後由 treemap.py 指令碼剖析。-vt 表示在輸出內容中納入 VMO 和執行緒。

傾印程序的詳細記憶體對應圖

如果您想瞭解特定程序為何使用這麼多記憶體,可以在其 koid 上執行 vmaps 工具 (執行 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'
...

您也可以使用 zxdb 中的 aspace 指令顯示記憶體對應。

傾印與程序相關聯的所有 VMO

vmos <pid>

這也會顯示未對應的 VMO,其中 psvmaps 目前並未列入考量。

也會顯示特定 VMO 是否為子項,以及其父項的 koid。

$ 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,此欄會顯示該控點具備零或多個以下的權利:
    • rZX_RIGHT_READ
    • wZX_RIGHT_WRITE
    • xZX_RIGHT_EXECUTE
    • mZX_RIGHT_MAP
    • dZX_RIGHT_DUPLICATE
    • tZX_RIGHT_TRANSFER
    • 注意:非帳號代碼項目在這一欄中會有一個「-」。
  • koid:VMO 的 koid (如有)。否則傳回 0。沒有 koid 的 VMO 是由核心建立,從未有使用者空間控制代碼。
  • 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)

您也可以使用 zxdb 中的 handle 指令顯示 VMO 資訊。

傾印「已隱藏」(未對應和核心) VMO

k zx vmos hidden

vmos <pid> 類似,但會傾印系統中未對應至任何程序的所有 VMO:

  • 使用者空間有控制代碼但不會對應的 VMO
  • 只對應到核心空間的 VMO
  • 僅限核心且未對應的 VMO,沒有帳號代碼

koid 值為 0 表示只有核心有該 VMO 的參照。

如果 #map 值為 0,表示 VMO 未對應到任何位址空間。

另請參閱k zx vmos all,這會傾印系統中的所有 VMO。注意:由於核心控制台的緩衝區限制,此輸出內容往往會遭到截斷,因此通常最好將 k zx vmos hidden 輸出內容與每個使用者程序的 vmaps 傾印結合。

限制

psvmaps 目前未將下列項目納入考量:

  • 未對應的 VMO 或 VMO 子範圍。舉例來說,您可以建立 VMO,將 1G 資料寫入其中,然後不會顯示在這裡。

任何程序傾印工具都無法說明以下事項:

  • 對應的頁面。如果您使用相同的 VMO 範圍建立多個對應關係,系統會將 VMO 的任何修訂頁面計為對應的頁面對應次數。這可能位於相同程序內,也可能在相同程序之間 (如果這些程序共用 VMO)。

    請注意,「相對應的網頁」包括寫入時複製。

  • 對程序分配的資源造成核心記憶體負擔。舉例來說,一項程序可能會開啟一百萬個處理點,而這些程序會耗用核心記憶體。

    您可以利用 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 的特定 VMO。
  • 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
...