Cum să utilizați comanda pmap pe Linux

Publicat: 2022-06-25
Laptop Linux afișează un prompt bash
fatmawati achmad zaenuri/Shutterstock.com

A afla cât de multă RAM folosește un proces Linux nu este o chestiune simplă, mai ales când trebuie luată în considerare memoria partajată. Din fericire, comanda pmap vă ajută să înțelegeți totul.

Maparea memoriei

Pe sistemele de operare moderne, fiecare proces trăiește în propria sa regiune alocată de memorie sau spațiu de alocare . Limitele regiunii alocate nu sunt mapate direct la adresele hardware fizice. Sistemul de operare creează un spațiu de memorie virtuală pentru fiecare proces și acționează ca un strat de abstractizare mapând memoria virtuală la memoria fizică.

Nucleul menține un tabel de traducere pentru fiecare proces, iar acesta este accesat de CPU. Când nucleul modifică procesul care rulează pe un anumit nucleu CPU, actualizează tabelul de traducere care leagă procesele și nucleele CPU.

Beneficiile abstracției

Există beneficii pentru această schemă. Utilizarea memoriei este oarecum încapsulată și sandbox pentru fiecare proces din țara utilizatorului. Un proces „vede” doar memoria în termeni de adrese de memorie virtuală. Aceasta înseamnă că poate funcționa numai cu memoria pe care i-a fost oferită de sistemul de operare. Cu excepția cazului în care are acces la o memorie partajată despre care nici nu știe și nici nu are acces la memoria alocată altor procese.

Ce este Swappiness pe Linux? (și cum se schimbă)
LEGATE Ce este Swappiness pe Linux? (și cum se schimbă)

Abstracția memoriei fizice bazate pe hardware în adrese de memorie virtuală permite nucleului să schimbe adresa fizică la care este mapată o memorie virtuală. Poate schimba memoria pe disc schimbând adresa reală către o regiune a memoriei virtuale. De asemenea, poate amâna furnizarea memoriei fizice până când este necesar.

Atâta timp cât solicitările de citire sau scriere a memoriei sunt deservite așa cum sunt solicitate, nucleul este liber să jongleze cu tabelul de mapare după cum crede de cuviință.

RAM la cerere

Tabelul de mapare și conceptul de „RAM la cerere” deschid posibilitatea memoriei partajate . Nucleul va încerca să evite încărcarea aceluiași lucru în memorie de mai multe ori. De exemplu, va încărca o bibliotecă partajată în memorie o dată și o va mapa la diferitele procese care trebuie să o utilizeze. Fiecare dintre procese va avea propria sa adresă unică pentru biblioteca partajată, dar toate vor indica aceeași locație reală.

Dacă regiunea de memorie partajată poate fi scrisă, nucleul folosește o schemă numită copy-on-write. Dacă un proces scrie în memoria partajată, iar celelalte procese care partajează acea memorie nu ar trebui să vadă modificările, se creează o copie a memoriei partajate în momentul solicitării de scriere.

Începător Geek: Cum să creați și să utilizați mașini virtuale
RELATED Începător Geek: Cum să creați și să utilizați mașini virtuale

Nucleul Linux 2.6.32, lansat în decembrie 2009, a oferit Linux o caracteristică numită „Imbinare Kernel SamePage”. Aceasta înseamnă că Linux poate detecta regiuni identice de date în spații de adrese diferite. Imaginează-ți o serie de mașini virtuale care rulează pe un singur computer și toate mașinile virtuale rulează același sistem de operare. Folosind un model de memorie partajată și copiere la scriere, supraîncărcarea pe computerul gazdă poate fi redusă drastic.

Toate acestea fac ca gestionarea memoriei în Linux să fie sofisticată și cât se poate de optimă. Dar această sofisticare face dificilă privirea unui proces și știi care este cu adevărat utilizarea memoriei acestuia.

Utilitarul pmap

Nucleul expune multe din ceea ce face cu RAM prin două pseudo-fișiere din pseudo-sistemul de fișiere cu informații de sistem „/proc”. Există două fișiere per proces, numite după ID-ul procesului sau PID -ul fiecărui proces: „/proc/maps” și „/proc//smaps”.

Instrumentul pmap citește informații din aceste fișiere și afișează rezultatele în fereastra terminalului. Va fi evident că trebuie să furnizăm PID-ul procesului de care suntem interesați de fiecare dată când folosim pmap .

Găsirea ID-ului procesului

Există mai multe moduri de a găsi PID-ul unui proces. Iată codul sursă pentru un program banal pe care îl vom folosi în exemplele noastre. Este scris în C. Tot ce face este să imprime un mesaj în fereastra terminalului și să aștepte ca utilizatorul să apese tasta „Enter”.

 #include <stdio.h>

int main(int argc, char *argv[])
{
  printf(„Programul de testare How-To Geek.”);
  getc(stdin);
} // sfârșitul principalului

Programul a fost compilat într-un executabil numit pm folosind compilatorul gcc :

 gcc -o pm pm.c 

Compilarea programului exemplu

Deoarece programul va aștepta ca utilizatorul să apese „Enter”, va rămâne în funcțiune atât timp cât ne dorim.

 ./p.m 

Rularea programului exemplu

Programul se lansează, tipărește mesajul și așteaptă apăsarea tastei. Acum putem căuta PID-ul său. Comanda ps listează procesele care rulează. Opțiunea -e (afișează toate procesele) face ca ps să listeze fiecare proces. Vom canaliza ieșirea prin grep și vom filtra intrările care au „pm” în numele lor.

 ps -e | grep pm 

Găsirea ID-ului procesului cu grep

Aceasta listează toate intrările cu „pm” oriunde în numele lor.

Putem fi mai specifici folosind comanda pidof . Oferim pidof numele procesului care ne interesează pe linia de comandă și încearcă să găsească o potrivire. Dacă se găsește o potrivire, pidof tipărește PID-ul procesului de potrivire.

 pidof pm 

Folosind pidof pentru a găsi ID-ul procesului

Metoda pidof este mai clară atunci când cunoașteți numele procesului, dar metoda ps va funcționa chiar dacă cunoașteți doar o parte din numele procesului.

Folosind pmap

Cu programul nostru de testare rulând și odată ce i-am identificat PID-ul, putem folosi pmap astfel:

 pmap 40919 

Rularea pmap pe programul exemplu

Mapările de memorie pentru proces sunt listate pentru noi.

Ieșirea pmap standard

Iată rezultatul complet al comenzii:

 40919: ./pm
000056059f06c000 4K r---- pm
000056059f06d000 4K rx-- pm
000056059f06e000 4K r---- pm
000056059f06f000 4K r---- pm
000056059f070000 4K rw--- pm
000056059fc39000 132K rw--- [ anon ]
00007f97a3edb000 8K rw--- [ anon ]
00007f97a3edd000 160K r---- libc.so.6
00007f97a3f05000 1616K rx-- libc.so.6
00007f97a4099000 352K r---- libc.so.6
00007f97a40f1000 4K ----- libc.so.6
00007f97a40f2000 16K r---- libc.so.6
00007f97a40f6000 8K rw--- libc.so.6
00007f97a40f8000 60K rw--- [ anon ]
00007f97a4116000 4K r---- ld-linux-x86-64.so.2
00007f97a4117000 160K rx-- ld-linux-x86-64.so.2
00007f97a413f000 40K r---- ld-linux-x86-64.so.2
00007f97a4149000 8K r---- ld-linux-x86-64.so.2
00007f97a414b000 8K rw--- ld-linux-x86-64.so.2
00007ffca0e7e000 132K rw--- [ stivă ]
00007ffca0fe1000 16K r---- [ anon ]
00007ffca0fe5000 8K rx-- [ anon ]
ffffffffff600000 4K --x-- [ anon ]
total 2756K

Prima linie este numele procesului și PID-ul acestuia. Fiecare dintre celelalte linii arată o adresă de memorie mapată și cantitatea de memorie de la acea adresă, exprimată în kiloocteți. Următoarele cinci caractere ale fiecărei linii se numesc permisiuni de memorie virtuală . Permisiunile valide sunt:

  • r : Memoria mapată poate fi citită de proces.
  • w : Memoria mapată poate fi scrisă prin proces.
  • x : Procesul poate executa orice instrucțiuni conținute în memoria mapată.
  • s : Memoria mapată este partajată, iar modificările aduse memoriei partajate sunt vizibile pentru toate procesele care partajează memoria.
  • R : Nu există nicio rezervare pentru spațiu de schimb pentru această memorie mapată.

Informația finală de pe fiecare linie este numele sursei mapării. Acesta poate fi un nume de proces, un nume de bibliotecă sau un nume de sistem, cum ar fi stiva sau heap.

Ecranul extins

Opțiunea -x (extinsă) oferă două coloane suplimentare.

 pmap -x 40919 

Folosind opțiunea extinsă -X cu pmap

Coloanelor li se dau titluri. Am văzut deja coloanele „Adresă”, „Kbytes”, „Mod” și „Mapping”. Noile coloane se numesc „RSS” și „Dirty”.

Ieșirea extinsă pmap

Iată rezultatul complet:

 40919: ./pm
Adresă Kbytes RSS Dirty Mode Mapping
000056059f06c000 4 4 0 r---- pm
000056059f06d000 4 4 0 rx-- pm
000056059f06e000 4 4 0 r---- pm
000056059f06f000 4 4 4 r---- pm
000056059f070000 4 4 4 rw--- pm
000056059fc39000 132 4 4 rw--- [ anon ]
00007f97a3edb000 8 4 4 rw--- [ anon ]
00007f97a3edd000 160 160 0 r---- libc.so.6
00007f97a3f05000 1616 788 0 rx-- libc.so.6
00007f97a4099000 352 64 0 r---- libc.so.6
00007f97a40f1000 4 0 0 ----- libc.so.6
00007f97a40f2000 16 16 16 r---- libc.so.6
00007f97a40f6000 8 8 8 rw--- libc.so.6
00007f97a40f8000 60 28 28 rw--- [ anon ]
00007f97a4116000 4 4 0 r---- ld-linux-x86-64.so.2
00007f97a4117000 160 160 0 rx-- ld-linux-x86-64.so.2
00007f97a413f000 40 40 0 ​​r---- ld-linux-x86-64.so.2
00007f97a4149000 8 8 8 r---- ld-linux-x86-64.so.2
00007f97a414b000 8 8 8 rw--- ld-linux-x86-64.so.2
00007ffca0e7e000 132 12 12 rw--- [ stivă ]
00007ffca0fe1000 16 0 0 r---- [ anon ]
00007ffca0fe5000 8 4 0 rx-- [ anon ]
ffffffffff600000 4 0 0 --x-- [ anon ]
---------------- ------- ------- ------- 
total kB 2756 1328 96
  • RSS : Aceasta este dimensiunea setului rezident . Adică, cantitatea de memorie care este în prezent în RAM și nu a fost schimbată.
  • Murdar : Memoria „murdară” a fost schimbată de când a început procesul și maparea.

Arată-mi totul

-X (chiar mai mult decât extins) adaugă coloane suplimentare la ieșire. Notați „X” majuscul. O altă opțiune numită -XX (chiar mai mult decât -X ) vă arată tot ce poate obține pmap din nucleu. Deoarece -X este un subset al lui -XX , vom descrie rezultatul de la -XX .

 pmap -XX 40919 

Folosind opțiunea -XX arată-mi totul cu pmap

Ieșirea se înfășoară îngrozitor într-o fereastră de terminal și este practic indescifrabilă. Iată rezultatul complet:

 40919: ./pm
         Adresă Perm Offset Dispozitiv Inode Dimensiune KernelPageSize MMUPageSize Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous LazyFree AnonHugePages ShmemPmdMapped FilePmdMapped Shared_Hugetlb Private_Hugetlb Swap Mappings Private_Hugetlbs Swap
    56059f06c000 r--p 00000000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm
    56059f06d000 r-xp 00001000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me dw sd pm
    56059f06e000 r--p 00002000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm
    56059f06f000 r--p 00002000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw ac sd pm
    56059f070000 rw-p 00003000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me dw ac sd pm
    56059fc39000 rw-p 00000000 00:00 0 132 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0rd wr mr mw me ac sd [heap]
    7f97a3edb000 rw-p 00000000 00:00 0 8 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd 
    7f97a3edd000 r--p 00000000 08:03 264328 160 4 4 160 4 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 rd mr mr mw sos 6d libc.
    7f97a3f05000 r-xp 00028000 08:03 264328 1616 4 4 788 32 788 0 0 0 788 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw.
    7f97a4099000 r--p 001bc000 08:03 264328 352 4 4 64 1 64 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me s.6 libc.
    7f97a40f1000 ---p 00214000 08:03 264328 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 mr mw me sd libc.so.6
    7f97a40f2000 r--p 00214000 08:03 264328 16 4 4 16 16 0 0 0 16 16 16 0 0 0 0 0 0 0 0 0 0 rd mr mwc me acsos 6 libc.
    7f97a40f6000 rw-p 00218000 08:03 264328 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd libc.
    7f97a40f8000 rw-p 00000000 00:00 0 60 4 4 28 28 0 0 0 28 28 28 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd 
    7f97a4116000 r--p 00000000 08:03 264305 4 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd ld82-6ux.
    7f97a4117000 r-xp 00001000 08:03 264305 160 4 4 160 11 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 0 rd-lin ex mrs 0 0 rd-lin ex mrs 4x8 me d-lin ex mr-x lx 6 d-lin ex mr.
    7f97a413f000 r--p 00029000 08:03 264305 40 4 4 40 1 40 0 ​​0 0 40 0 ​​0 0 0 0 0 0 0 0 0 0 rd mr mr mr mw me dw 6ux-sod.
    7f97a4149000 r--p 00032000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw ac sd l86-64.x ld.
    7f97a414b000 rw-p 00034000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr mr mr mw me dw ac s4x-d lx82-6-lin
    7ffca0e7e000 rw-p 00000000 00:00 0 132 4 4 12 12 0 0 0 12 12 12 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me gd ac [stiva]
    7ffca0fe1000 r--p 00000000 00:00 0 16 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rd mr pf io de dd sd [vvar]
    7ffca0fe5000 r-xp 00000000 00:00 0 8 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me de sd [vdso]
ffffffffff600000 --xp 00000000 00:00 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ex [vsyscall]
                                             ==== ============== =========== ==== === ============ == ========== =========================== ========== ==== ===== ======== ============= ========================= === ============== ================ ==== ======== ======= ========== 
                                             2756 92 92 1328 157 1220 0 12 96 1328 96 0 0 0 0 0 0 0 0 0 0 KB 

Există o mulțime de informații aici. Iată ce rețin coloanele:

  • Adresă : adresa de început a acestei mapări. Aceasta folosește adresarea memoriei virtuale.
  • Perm : permisiunile memoriei.
  • Offset : Dacă memoria este bazată pe fișiere, offset-ul acestei mapări în interiorul fișierului.
  • Dispozitiv : numărul dispozitivului Linux, dat în numere majore și minore. Puteți vedea numerele dispozitivului de pe computer rulând comanda lsblk .
  • Inode : inodul fișierului cu care este asociată maparea. De exemplu, în exemplul nostru, acesta ar putea fi inodul care deține informații despre programul pm.
  • Dimensiune : dimensiunea regiunii mapate în memorie.
  • KernelPageSize : dimensiunea paginii utilizată de nucleu.
  • MMUPageSize : dimensiunea paginii utilizată de unitatea de gestionare a memoriei.
  • Rss : Aceasta este dimensiunea setului rezident . Adică, cantitatea de memorie care este în prezent în RAM și nu a fost schimbată.
  • Pss : Aceasta este dimensiunea proporțională a acțiunii. Aceasta este dimensiunea partajată privată adăugată la (dimensiunea partajată împărțită la numărul de acțiuni.)
  • Shared_Clean : cantitatea de memorie partajată cu alte procese care nu a fost modificată de când a fost creată maparea. Rețineți că, chiar dacă memoria poate fi partajată, dacă nu a fost partajată, este totuși considerată memorie privată.
  • Shared_Dirty : cantitatea de memorie partajată cu alte procese care a fost modificată de când a fost creată maparea.
  • Private_Clean : cantitatea de memorie privată, care nu a fost partajată cu alte procese, care nu a fost modificată de când a fost creată maparea.
  • Private_Dirty : cantitatea de memorie privată care a fost modificată de când a fost creată maparea.
  • Referit : cantitatea de memorie marcată în prezent ca referită sau accesată.
  • Anonim : memorie care nu are un dispozitiv pe care să se schimbe. Adică, nu este susținut de fișiere.
  • LazyFree : Pagini care au fost semnalate ca MADV_FREE . Aceste pagini au fost marcate ca disponibile pentru a fi eliberate și revendicate, chiar dacă pot avea modificări nescrise în ele. Totuși, dacă apar modificări ulterioare după ce MADV_FREE a fost setat pe maparea memoriei, steag-ul MADV_FREE este eliminat și paginile nu vor fi recuperate până când modificările sunt scrise.
  • AnonHugePages : Acestea sunt pagini de memorie „uriașe” care nu sunt susținute de fișiere (mai mari de 4 KB).
  • ShmemPmdMapped : memorie partajată asociată cu pagini uriașe. Ele pot fi utilizate și de sistemele de fișiere care se află în întregime în memorie.
  • FilePmdMapped : Directorul de mijloc al paginii este una dintre schemele de paginare disponibile pentru nucleu. Acesta este numărul de pagini susținute de fișiere indicate de intrările PMD.
  • Shared_Hugetlb : Translation Lookaside Tables, sau TLB, sunt cache-uri de memorie utilizate pentru a optimiza timpul necesar pentru a accesa locațiile de memorie ale spațiului utilizatorului. Această cifră este cantitatea de RAM utilizată în TLB-uri care sunt asociate cu pagini de memorie uriașă partajată.
  • Private_Hugetlb : Această cifră este cantitatea de RAM utilizată în TLB-uri care sunt asociate cu paginile private de memorie uriașă.
  • Swap : cantitatea de swap utilizată.
  • SwapPss : Mărimea acțiunii proporționale de swap . Aceasta este cantitatea de schimb alcătuită din pagini de memorie privată schimbate adăugate la (dimensiunea partajată împărțită la numărul de partajări).
  • Blocat : mapările memoriei pot fi blocate pentru a împiedica sistemul de operare să paginați memoria heap sau off-heap.
  • THPeligible : Acesta este un semnalizare care indică dacă maparea este eligibilă pentru alocarea de pagini mari transparente . 1 înseamnă adevărat, 0 înseamnă fals. Pagini uriașe transparente este un sistem de gestionare a memoriei care reduce supraîncărcarea căutărilor de pagini TLB pe computerele cu o cantitate mare de RAM.
  • VmFlags : vezi lista de steaguri de mai jos.
  • Mapping : numele sursei mapării. Acesta poate fi un nume de proces, un nume de bibliotecă sau nume de sistem, cum ar fi stiva sau heap.

VmFlags—steaguri de memorie virtuală—va fi un subset al listei următoare.

  • rd : Citibil.
  • wr : Inscriptibil.
  • ex : Executabil.
  • sh : Partajat.
  • mr : Poate citi.
  • mw : Poate scrie.
  • eu : Poate executa.
  • ms : Poate distribui.
  • gd : Segmentul de stivă crește în jos.
  • pf : Interval pur de numere a cadrelor de pagină. Numerele cadrelor de pagină sunt o listă a paginilor de memorie fizică.
  • dw : scrierea dezactivată în fișierul mapat.
  • lo : Paginile sunt blocate în memorie.
  • io : zonă I/O mapată în memorie.
  • sr : sfaturi de citire secvențială oferite (de funcția madvise() .)
  • rr : Sfatul de citire aleatoriu oferit.
  • dc : Nu copiați această regiune de memorie dacă procesul este bifurcat.
  • de : Nu extindeți această regiune de memorie la remapare.
  • ac : Zona este responsabilă.
  • nr : Spațiul de schimb nu este rezervat zonei.
  • ht : Zona utilizează pagini TLB uriașe.
  • sf : Eroare de pagină sincronă.
  • ar : steag specific arhitecturii.
  • wf : Ștergeți această regiune de memorie dacă procesul este bifurcat.
  • dd : Nu includeți această regiune de memorie în depozitele de bază.
  • sd : Steagul moale și murdar.
  • mm : zonă de hartă mixtă.
  • hg : steag de consiliere de pagină uriașă.
  • nh : Nicio pagină uriașă de consiliere.
  • mg : Indicator de consiliere fuzionabil.
  • bt : ARM64 bias temperatură instabilitate pagină protejată.
  • mt : ARM64 Etichetele extensiei de etichetare a memoriei sunt activate.
  • um : Userfaultfd lipsește urmărirea.
  • uw : Urmărire Userfaultfd wr-protect.

Managementul memoriei este complicat

Și este dificil să lucrezi înapoi din tabele de date pentru a înțelege ce se întâmplă de fapt. Dar cel puțin pmap vă oferă imaginea completă, astfel încât să aveți cele mai bune șanse să vă dați seama ce trebuie să știți.

Este interesant de observat că programul nostru exemplu a fost compilat într-un executabil binar de 16 KB și totuși folosește (sau partajează) aproximativ 2756 KB de memorie, aproape în întregime datorită bibliotecilor de rulare.

Un ultim truc bun este că puteți utiliza pmap și pidof împreună, combinând acțiunile de a găsi PID-ul procesului și de a-l transmite către pmap într-o singură comandă:

 pmap $(pidof pm)