Jarayon xotirasi: virtual manzil maydoni, RSS va OOM killer
ps -o vsz,rss va top ning xotira ustunlari har bir jarayon uchun ikkita son ko'rsatadi va bitta jarayon uchun ular hech qanday xatosiz o'n barobar farq qilishi mumkin. Jarayon 2 GB virtual hajmni ko'rsatib, 512 MB RAM’li mashinada mutlaqo bemalol ishlashi mumkin, chunki virtual hajm va haqiqiy xotira sarfi ikki xil savolga javob beradi. Ularni adashtirish noto'g'ri "xotira tugadi" tashxisining eng keng tarqalgan sabablaridan biri — boshqa tomondan esa haqiqiy xotira oqishi (leak) kernelning OOM killer’i jarayonlarni o'ldira boshlamaguncha sezilmay qolishining sababi.
Bu maqola top ning umumiy xotira qatori tilga olingan, lekin tushuntirilmagan Jarayonlarni kuzatish maqolasiga tayanadi va jarayon xotirasini to'g'ri o'qish uchun kerakli atamalar va buyruqlarni beradi: virtual va rezident hajm, umumiy va shaxsiy sahifalar, swap xatti-harakati va tizimda xotira haqiqatan tugaganda Out-Of-Memory killer qaysi jarayonni qurbon qilishni qanday hal qilishi.
Virtual xotira: har bir jarayonga o'z manzil maydoni beriladi
Linux’dagi har bir jarayon o'zining virtual manzil maydoni ichida ishlaydi — bu jarayon kodi ishlatadigan shaxsiy manzillar oralig'i. Kernel va CPU’ning xotirani boshqarish bloki (MMU) ularni orqa fonda haqiqiy jismoniy RAM ga (yoki swap’ga chiqarilgan sahifalar uchun diskka) tarjima qiladi. Ikki bog'liq bo'lmagan jarayon hech qanday ziddiyatsiz 0x400000 manziliga murojaat qila oladi, chunki har bir jarayonning 0x400000 i butunlay alohida jismoniy xotiraga mos keladi.
Aynan shu abstraksiya tufayli bitta jarayonga katta virtual hajm (VSZ) berilishi mumkin va bu son haqiqiy xotira bosimini aks ettirmaydi. VSZ quyidagilarni o'z ichiga oladi:
- jarayonning o'z kodi va ma’lumotlari;
- u xotiraga ulagan har bir umumiy kutubxona — garchi bu kutubxonalarni ta’minlovchi jismoniy sahifalar xuddi shu kutubxonani ishlatadigan boshqa har bir jarayon bilan ulashilsa ham;
- jarayon zaxiralagan (masalan,
mallocorqali), lekin hech qachon ishlatmagan xotira — Linux sahifaga birinchi marta yozilmaguncha uni jismoniy RAM bilan ta’minlamaydi, bu xatti-harakat talab bo'yicha sahifalash (demand paging) deyiladi; - xotiraga ulangan (memory-mapped) fayllar.
Shuning uchun jarayon faqat katta umumiy kutubxonalarni ulagani va to'liq ishlatmaydigan manzil maydonini zaxiralagani hisobiga bir necha gigabaytlik VSZ ni ko'rsatishi mumkin.
Resident Set Size: RAM’da aslida nima bor
RSS (Resident Set Size) — jarayon virtual xotirasining hozir haqiqiy jismoniy sahifalar bilan ta’minlangan qismi. Bu aynan shu lahzadagi RAM sarfiga haqiqatan mos keladigan son.
VSZ va RSS sukut bo'yicha kibibaytlarda ko'rsatiladi. Bu yerda postgres taxminan 400 MB manzil maydonini zaxiralagan, lekin hozir haqiqiy RAM’ning taxminan 183 MB ida turibdi. Farq — ishlatilmagan zaxira, jismonan ulashilsa ham har bir jarayon uchun bir martadan hisoblanadigan umumiy kutubxona ulanishlari va bir marta ishlatilib, keyinroq kernel tomonidan qaytarib olingan sahifalar.
Warning
Umumiy xotira sarfini baholash uchun barcha jarayonlarning RSS ini qo'shib chiqish, jarayonlar xotirani ulashganda haqiqiy sarfni muntazam ravishda oshirib hisoblaydi. Ko'pincha bu bitta serverning bir nechta ishchi jarayonlari (bir nechta nginx yoki PHP-FPM ishchilari) bir xil umumiy kutubxonalarni va ba’zi arxitekturalarda umumiy xotira segmentlarini ulaganda yuz beradi. Har bir ishchining RSS i o'sha umumiy sahifalarni to'liq o'z ichiga oladi, shuning uchun har biri 40 MB RSS ko'rsatayotgan o'nta ishchi 400 MB noyob jismoniy xotira ishlatilayotganini bildirishi shart emas.
PSS: jarayon uchun adolatliroq son
PSS (Proportional Set Size) aynan shu oshirib hisoblash muammosini hal qiladi: u har bir umumiy sahifaning "narxini" uni ulagan har bir jarayon o'rtasida mutanosib ravishda bo'ladi. smem (Debian/Ubuntu’da sudo apt install smem bilan o'rnatiladi) uni to'g'ridan-to'g'ri ko'rsatadi:
PID Command RSS PSS USS
2201 nginx: worker process 9.8M 5.1M 3.2M
2202 nginx: worker process 9.7M 5.0M 3.1M
1842 nginx: master process 8.4M 6.9M 6.4M
-------------------------------------------------------
Total 27.9M 17.0M 12.7M
USS (Unique Set Size) — faqat shu bitta jarayon ushlab turgan, hech narsa bilan ulashilmagan xotira. Bu "aynan shu jarayonning o'zi o'ldirilsa, qancha xotira haqiqatan bo'shaydi" degan savol uchun eng aniq ko'rsatkich. PSS esa xizmatning haqiqiy umumiy hajmini baholash uchun jarayonlar bo'yicha qo'shib chiqish mumkin bo'lgan eng adolatli son, chunki umumiy sahifalar jami bir marta hisoblanadi va har bir jarayon o'rtasida ulush sifatida bo'linadi.
/proc bu yerda qanday o'rin tutadi
ps va top jarayon uchun ko'rsatadigan har bir son oxir-oqibat shu jarayonning /proc ostidagi o'z katalogidan olinadi — bu /proc fayl tizimi maqolasida chuqur yoritilgan. Aynan xotira uchun:
VmSwap ni alohida tekshirishga arziydi: bu yerdagi noldan farqli qiymat aynan shu jarayonning bir qismi swap’ga chiqarilganini bildiradi. Bu, hatto umumiy vositada tizim xotirasi yaxshi ko'rinsa ham, keyingi murojaatda sezilarli darajada sekinroq javobga olib kelishi mumkin.
free -h ni to'g'ri o'qish
total used free shared buff/cache available
Mem: 15Gi 9.4Gi 411Mi 412Mi 5.6Gi 4.0Gi
Swap: 2.0Gi 1.8Gi 157Mi
Bu har qanday Linux tizimida eng ko'p noto'g'ri o'qiladigan qator. free ustunidagi qiymat xavotirli darajada past ko'rinadi, lekin u faqat umuman hech narsa saqlamayotgan xotirani hisoblaydi — u buff/cache ni, ya’ni kernel aks holda bo'sh turadigan RAM’ni disk bloklari va yaqinda ishlatilgan fayllarni keshlash uchun ishlatayotgan qismni hisoblamaydi. Bu kesh isrof qilingan xotira emas: u foydali ish bajarayotgan xotira (xuddi shu ma’lumot keyingi safar kerak bo'lganda diskdan o'qishning oldini oladi) va kernel ilovaga haqiqatan ko'proq kerak bo'lishi bilan uni darhol qaytarib olib, berib yuboradi.
"Yangi jarayon hozir xotira ola oladimi" degan savol uchun muhim ustun — available. Bu kernelning qaytarib olinadigan keshni hisobga olgan holda, swap’siz yangi ajratishlar uchun bo'shatilishi mumkin bo'lgan xotira haqidagi o'z bahosi. Bu yerda free faqat 411Mi ni ko'rsatsa ham, aniq ko'rsatkich — 4.0Gi available.
Intervyuda
"Serveringiz 16 GB dan 400 MB bo'sh ko'rsatyapti — xotira tugash arafasidami?" — keng tarqalgan hiyla savol. To'g'ri javob free dan emas, buff/cache va available dan boshlanadi. Faqat available xotiradagi doimiy bosim, o'sib borayotgan swap sarfi (Swap: used ning ko'tarilishi) va oxir-oqibat kernel logida xotirani qaytarib olish haqidagi xabarlar haqiqiy xotira bosimini ko'rsatadi. Katta buff/cache va sog'lom available ko'rsatkichi — ogohlantirish belgisi emas, odatdagidek ishlayotgan, yaxshi foydalanilayotgan tizim.
Swap: qo'shimcha RAM emas, xavfsizlik to'ri
Swap maydoni kernelga kam ishlatiladigan sahifalarni RAM’dan diskka ko'chirishga imkon beradi va shu bilan faolroq foydalanish uchun jismoniy xotirani bo'shatadi. U tezlik jihatidan RAM’ning o'rnini bosmaydi: swap’dan qondirilishi kerak bo'lgan page fault RAM’dan qondiriladigandan bir necha tartib sekinroq, chunki u disk (yoki SSD) I/O amalini talab qiladi.
NAME TYPE SIZE USED PRIO
/swap.img file 2G 1.8G -2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 2 1843200 421200 812400 5872000 4 12 180 420 2210 3890 18 6 68 8 0
Tizim yuklama ostida bo'lganda vmstat dagi noldan farqli, doimiy si/so (swap in/swap out) — faol swap thrashing'ning eng aniq belgisi: sahifalar diskka va diskdan qayta-qayta ko'chiriladi va bu unumdorlikni faqat "ishlatilgan" swap foizi ko'rsatadigandan ancha ko'proq yomonlashtiradi. Swap’ining 90% i ishlatilgan, lekin si/so ikkalasi ham doim 0 bo'lgan tizim faol thrashing qilmayapti: u shunchaki bir marta ba’zi "sovuq" sahifalarni chiqarib, ularni o'sha yerda qoldirgan.
OOM killer
Kernel xotira ajratish so'rovini haqiqatan qondira olmaganda — bo'sh RAM yo'q, swap tugagan yoki o'chirilgan va keshni qaytarib olish yetarli emas — butun tizim qotib qolishiga (deadlock) yo'l qo'yish o'rniga u OOM (Out-Of-Memory) killer ni ishga tushiradi. OOM killer to'xtatiladigan jarayonni har bir jarayon uchun hisoblanadigan va to'g'ridan-to'g'ri o'qish mumkin bo'lgan ichki oom_score asosida tanlaydi:
cat /proc/$(pgrep -x postgres | head -1)/oom_score
cat /proc/$(pgrep -x postgres | head -1)/oom_score_adj
Yuqoriroq oom_score jarayonni nishonga olinish ehtimoli yuqoriroq qiladi. Bu ball jarayon qancha xotira ishlatayotganiga kuchli bog'liq va uni oom_score_adj bilan qo'lda o'zgartirish mumkin: qiymat -1000 (bu jarayonni hech qachon OOM nishoni sifatida o'ldirma) dan 1000 (birinchi bo'lib shuni o'ldir) gacha. Muhim tizim jarayoniga -1000 qo'yish (buni systemd ko'pincha o'zining asosiy unit’lari uchun avtomatik qiladi) uni hech qachon tanlanmasligidan himoya qiladi, lekin tizimni xotira tugashidan himoya qilmaydi — uning o'rniga baribir boshqa narsa o'ldiriladi.
Jul 29 03:14:02 web01 kernel: Out of memory: Killed process 18422 (java) total-vm:4213212kB, anon-rss:3921004kB, ...
Bu kernel log yozuvi — OOM tomonidan o'ldirilganining aniq qaydi. total-vm va anon-rss ko'rsatkichlari o'ldirilgan jarayon to'xtatilgan paytda aynan qancha xotira ishlatayotganini ko'rsatadi. Bu haqiqiy xotira oqishi bo'lganmi yoki qonuniy ish yukining o'sishi uchun shunchaki kichik qilib belgilangan xotira chegarasimi — shuni aniqlashning boshlang'ich nuqtasi.
Danger
Takrorlanuvchi OOM kill’larni swap’ni o'chirib yoki oqibatini tushunmasdan vm.overcommit_memory ni erkin qiymatga o'rnatib "tuzatmang". Swap’ni o'chirish kernel OOM killer’ga murojaat qilishdan oldin foydalanadigan xavfsizlik zaxirasini olib tashlaydi va bu odatda kernelni uni kamroq emas, ertaroq ishga tushirishga majbur qiladi. Alomatni emas, haqiqiy sababni bartaraf eting — xotira oqayotgan jarayon, kichik qilib belgilangan konteyner xotira chegarasi yoki ish yuki uchun haqiqatan yetarli bo'lmagan RAM.
Real vaziyat: xotira oqishini keshning odatiy o'sishidan ajratish
Muammo. Ilova serverida free -h bir necha kun davomida xotira sarfi barqaror o'sib borayotganini ko'rsatyapti va jamoadoshingiz xizmatni "har ehtimolga qarshi" qayta ishga tushirmoqchi. Buni qilishdan oldin dalil kerak: bu ilovadagi haqiqiy oqishmi yoki kernel shunchaki keshga ko'proq RAM ishlatyaptimi — bu kutilgan va zararsiz holat.
Avval umumiy manzarani tekshiring:
Agar available sog'lom bo'lib qolsa va asosan buff/cache o'sayotgan, used (kesh bo'lmagan ko'rsatkich) esa o'zgarmayotgan bo'lsa, bu oqishga emas, keshning odatiy o'sishiga ishora qiladi — "shunchaki qayta ishga tushiraylik" rejasini davom ettirmang.
Agar used (kesh emas) haqiqatan o'sayotgan bo'lsa, muayyan jarayonni ajrating:
Xuddi shu buyruqni bir necha soat davomida har soatda ishga tushiring (yoki natijani logga yozadigan kichik skript bilan yig'ing):
PID ELAPSED RSS VSZ
22110 18000 412300 1820400
PID ELAPSED RSS VSZ
22110 21600 498100 1820400
PID ELAPSED RSS VSZ
22110 25200 583900 1820400
Sog'lom holatda kutiladigan natija. Ilova barqaror ishchi to'plamga yetgach, RSS bir darajada to'xtashi kerak. Keshlar "qizib" borayotganda boshida biroz o'sish odatiy, lekin barqaror, takrorlanuvchi ish yuki ostida u o'sishdan to'xtashi kerak.
Xulosa. Bu misolda barqaror bo'lishi kerak bo'lgan ish yuki ostida RSS o'tgan vaqtga mutanosib ravishda deyarli chiziqli o'syapti, VSZ esa o'zgarmayapti. Bu kesh xatti-harakati emas, ilova ichidagi haqiqiy xotira oqishining kuchli belgisi (VSZ ning o'zgarmasligi jarayon shunchaki ishlatmasdan ko'proq manzil maydonini zaxiralayotgani ehtimolini ham istisno qiladi). Tuzatish ilovaga tegishli: profiler (masalan, tilga xos heap analizatori) yoki vaqtinchalik chora sifatida xotira chegarasi bilan qayta ishga tushirish siyosati. Jarayonni qayta ishga tushirish faqat xuddi shu o'sishning qaytalanishini kechiktiradi va o'z-o'zidan tashxis bo'lmaydi.
Keng tarqalgan xatolar
VSZ ni haqiqiy xotira sarfi deb o'qish
VSZ zaxiralangan, lekin ishlatilmagan manzil maydonini va har bir umumiy kutubxona ulanishini o'z ichiga oladi. Haqiqiy xotira sarfiga o'xshash har qanday da’vo uchun RSS dan, yaxshisi esa smem dagi PSS/USS dan foydalaning.
free’dagi "free" ustunini mavjud xotira deb hisoblash
free -h dagi free qaytarib olinadigan keshni o'z ichiga olmaydi. Tizimda haqiqatan xotira yetishmayaptimi degan har qanday qaror uchun available ustunidan foydalaning.
Ishchi jarayonlar bo'yicha RSS ni qo'shib chiqish
Bitta xizmatning bir nechta ishchilari kutubxona va ko'pincha umumiy xotira segmenti sahifalarini ulashadi. Ularning RSS qiymatlari o'sha umumiy xotirani ikki marta hisoblaydi; aniq jami uchun smem dagi PSS dan foydalaning.
Faqat yuqori swap sarfi muammo degani deb o'ylash
vmstat da si/so ikkalasi ham nolga yaqin bo'lgan holda katta hajmdagi ishlatilgan swap "sovuq" sahifalar bir marta chiqarilib, shunchaki o'sha yerda turganini bildiradi — bu unumdorlikka faol zarar yetkazmaydi. Haqiqiy thrashing uchun xom swap foiziga emas, si/so ga qarang.
OOM kill’larni "hal qilish" uchun swap’ni o'chirish
Swap’ni olib tashlash kernel OOM killer’ni ishga tushirishdan oldin foydalanadigan buferni yo'q qiladi va odatda bosim ostida xotira tugashi tufayli o'ldirishlar kechroq emas, ertaroq sodir bo'lishiga olib keladi. Avval haqiqiy xotira iste’molchisini aniqlang.
Mashqlar
- O'z tizimingizda
ps -eo pid,comm,vsz,rss --sort=-rss | headni bajaring va eng yuqoridagi jarayon uchun uningVSZi negaRSSidan katta bo'lishi ehtimolini taxminan tushuntiring. smemni o'rnating va bir nechta ishchi jarayonga ega xizmat uchun (yoki mavjud bo'lsanginx/PHP-FPM; aks holda umumiy interpretatorni ulashadigan kichik skriptning bir nechta nusxasini ishga tushiring)RSSvaPSSni solishtiring. Farqning yo'nalishi va taxminiy hajmini tushuntiring.free -hni bajaring va qaysi ko'rsatkich yangi jarayon uchun haqiqatan mavjud xotirani ifodalashini aniqlang, shuningdek faqat "free" ustuni nega chalg'ituvchi javob bergan bo'lishini tushuntiring.- Hech qanday buzuvchi amal bajarmasdan, jarayonga
-1000qilib o'rnatilganoom_score_adjnimadan himoya qilishini va nimadan himoya qilmasligini tushuntiring. Haqiqiy OOM kill hodisasi qanday ko'rinishini bilish uchun yuqorida ko'rsatilgan kernel log formatiga tayaning.
Mashqni bajardim deyish uchun: javoblaringizdagi "jarayon qancha xotira ishlatadi" degan har qanday da’vo RSS, PSS yoki USS ni aniq ko'rsatishi va berilgan aniq savol uchun ulardan qaysi biri o'rinli ekanini tushuntirishi kerak — faqat VSZ bu mashqlarning hech biriga qabul qilinadigan javob emas.
Manbalar
- Linux man-pages:
proc(5)—/proc/[pid]/status,/proc/meminfo: https://man7.org/linux/man-pages/man5/proc.5.html - Linux kernel hujjatlari: overcommit accounting: https://www.kernel.org/doc/html/latest/mm/overcommit-accounting.html
- Linux kernel hujjatlari: the OOM killer: https://www.kernel.org/doc/gorman/html/understand/understand016.html
- Linux man-pages:
free(1): https://man7.org/linux/man-pages/man1/free.1.html - Linux man-pages:
vmstat(8): https://man7.org/linux/man-pages/man8/vmstat.8.html - Linux man-pages:
smem(8): https://man7.org/linux/man-pages/man8/smem.8.html - Red Hat Enterprise Linux 9: understanding memory and swap: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/monitoring_and_managing_system_status_and_performance/index
- Linux kernel hujjatlari:
oom_score,oom_score_adj: https://www.kernel.org/doc/html/latest/filesystems/proc.html