พิจารณาการใช้งานหน่วยความจำอย่างถูกต้องใน Linux


63

ฉันสับสนเล็กน้อยในบางส่วนของผลลัพธ์ที่ผมเห็นจากPSและฟรี

บนเซิร์ฟเวอร์ของฉันนี่คือผลลัพธ์ของ free -m

[root@server ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          2048       2033         14          0         73       1398
-/+ buffers/cache:        561       1486
Swap:         2047         11       2036

ความเข้าใจของฉันเกี่ยวกับวิธีที่ Linux จัดการหน่วยความจำคือมันจะเก็บการใช้งานดิสก์ใน RAM เพื่อให้การเข้าถึงแต่ละครั้งนั้นเร็วขึ้น ฉันเชื่อว่าสิ่งนี้ถูกระบุโดยคอลัมน์ "แคช" นอกจากนี้บัฟเฟอร์ต่าง ๆ จะถูกเก็บไว้ใน RAM ตามที่ระบุในคอลัมน์ "บัฟเฟอร์"

ดังนั้นถ้าฉันเข้าใจถูกต้องการใช้ "จริง" ควรจะเป็นค่า "ใช้แล้ว" ของ "- / + บัฟเฟอร์ / แคช" หรือ 561 ในกรณีนี้

ps auxดังนั้นสมมติว่าทั้งหมดที่ถูกต้องส่วนที่พ่นฉันก็คือผลของการ

ความเข้าใจของฉันเกี่ยวกับpsผลลัพธ์คือคอลัมน์ที่ 6 (RSS) แสดงขนาดเป็นกิโลไบต์ที่กระบวนการใช้สำหรับหน่วยความจำ

ดังนั้นเมื่อฉันเรียกใช้คำสั่งนี้:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

ผลลัพธ์ไม่ควรเป็นคอลัมน์ "ใช้แล้ว" ของ "- / + บัฟเฟอร์ / แคช" free -mใช่หรือไม่

ดังนั้นฉันจะตรวจสอบการใช้หน่วยความจำของกระบวนการใน Linux ได้อย่างไร? เห็นได้ชัดว่าตรรกะของฉันมีข้อบกพร่อง


คำถามนี้ค่อนข้างเป็นที่นิยมและฉันคิดว่าฉันควรแบ่งปันคำตอบของhtopผู้เขียนกับคำถามที่คล้ายกันหนึ่งคำถามที่ฉันมีในวันอื่น ... วิธีการคำนวณการใช้หน่วยความจำจาก / proc / meminfo (เช่น htop)
tgogos

คำตอบ:


57

นี้แน่นอนคำถามเดียวกันถูกถามในServerFaultเพียงวันอื่น ๆ :-)

ระบบหน่วยความจำเสมือนของ linux นั้นไม่ง่ายนัก คุณไม่สามารถเพียงแค่เพิ่มขึ้นทุกเขตข้อมูล RSS และได้รับค่าที่รายงานโดยused freeมีเหตุผลหลายประการสำหรับเรื่องนี้ แต่ฉันจะไปถึงสองคนที่ใหญ่ที่สุด

  • เมื่อกระบวนการดึงทั้งผู้ปกครองและเด็กจะแสดงด้วย RSS เดียวกัน อย่างไรก็ตาม linux ใช้งานcopy-on-writeเพื่อให้กระบวนการทั้งสองใช้หน่วยความจำเดียวกันจริงๆ เฉพาะเมื่อหนึ่งในกระบวนการปรับเปลี่ยนหน่วยความจำมันจะถูกทำซ้ำจริง ดังนั้นสิ่งนี้จะทำให้freeจำนวนนั้นน้อยกว่าtopผลรวม RSS

  • ค่า RSS ไม่รวมหน่วยความจำที่แชร์ เนื่องจากหน่วยความจำที่ใช้ร่วมกันไม่ได้เป็นเจ้าของโดยกระบวนการใดกระบวนการหนึ่งtopจึงไม่รวมอยู่ใน RSS ดังนั้นสิ่งนี้จะทำให้freeจำนวนนั้นมากกว่าtopผลรวม RSS


1
นี่คือคำตอบที่ดีที่สุดที่ฉันได้รับในเว็บไซต์แลกเปลี่ยนกองซ้อนจนถึงปัจจุบัน ดังนั้นโดยเฉพาะสิ่งที่ฉันอยากรู้ โดยเฉพาะอย่างยิ่งกับสถานการณ์ของฉันเพราะฉันกำลังจัดการกับโปรแกรมที่ฉันเขียนส้อมกระบวนการ แต่ส่วนใหญ่ของรอยเท้าอยู่ในห้องสมุดที่พวกเขาใช้
GoldenNewby

ปัญหาของคำตอบนี้คือการคำนวณผลรวมของ RSS และ SHR มักให้หน่วยความจำน้อยกว่ามาก ตัวอย่างเช่นใน VPS ที่ฉันมีหน่วยความจำที่ใช้คือ 380MB ในขณะที่ผลรวมของ RSS และ SHR ทั้งหมดคือ 90MB
user239558

2
@ user239558 ดังที่ฉันได้กล่าวไว้ในคำตอบมีหลายสาเหตุที่ตัวเลขไม่เพิ่มขึ้นฉันแสดงรายการเพียง 2 รายการเท่านั้น มีตัวเลขอื่น ๆ อีกมากมาย แคช, แผ่นพื้น, หน้าใหญ่ ฯลฯ
Patrick

2
น่าจะเป็นปีต่อมาหลังจากที่คุณตอบคำถามนี้ฉันยังมี (อย่างน้อย) หนึ่งความสับสน คุณบอกว่าค่า RSS ไม่รวมหน่วยความจำที่ใช้ร่วมกัน แต่คำตอบนี้บอกว่า "มันรวมหน่วยความจำจากไลบรารีที่ใช้ร่วมกันตราบเท่าที่หน้าจากไลบรารีเหล่านั้นอยู่ในหน่วยความจำจริง" ตอนนี้ฉันไม่รู้ว่าใครจะเชื่อ ... บางทีฉันอาจพลาดความแตกต่างเล็กน้อยที่นี่ ...
Naitree

1
@Naitree "shared libraries"! = "หน่วยความจำแบบแบ่งใช้" หน่วยความจำที่ใช้ร่วมกันเป็นสิ่งที่ชอบหรือshmget mmapการใช้ถ้อยคำรอบ ๆ หน่วยความจำนั้นยุ่งยากมาก การใช้คำผิดในที่ที่ผิดสามารถทำให้ความหมายของประโยคผิดไปหมด
แพทริค

30

หากคุณกำลังมองหาหมายเลขหน่วยความจำที่เพิ่มขึ้นดูsmem :

smem เป็นเครื่องมือที่สามารถให้รายงานจำนวนมากเกี่ยวกับการใช้หน่วยความจำบนระบบ Linux ซึ่งแตกต่างจากเครื่องมือที่มีอยู่ smem สามารถรายงานขนาดชุดสัดส่วน (PSS) ซึ่งเป็นตัวแทนที่มีความหมายมากกว่าจำนวนหน่วยความจำที่ใช้โดยไลบรารีและแอปพลิเคชันในระบบหน่วยความจำเสมือน

เนื่องจากโดยทั่วไปแล้วส่วนใหญ่ของหน่วยความจำกายภาพจะถูกใช้ร่วมกันในหลาย ๆ แอปพลิเคชันการวัดมาตรฐานการใช้งานหน่วยความจำที่รู้จักกันในชื่อชุดขนาดอาศัย (RSS) จะทำให้การใช้งานหน่วยความจำสูงเกินไปอย่างมีนัยสำคัญ PSS จะวัดการ "แบ่งปันที่เป็นธรรม" ของแต่ละแอปพลิเคชันของแต่ละพื้นที่ที่ใช้ร่วมกันเพื่อให้การวัดที่สมจริง

ตัวอย่างที่นี่:

# smem -t
  PID User     Command                         Swap      USS      PSS      RSS
...
10593 root     /usr/lib/chromium-browser/c        0    22868    26439    49364 
11500 root     /usr/lib/chromium-browser/c        0    22612    26486    49732 
10474 browser  /usr/lib/chromium-browser/c        0    39232    43806    61560 
 7777 user     /usr/lib/thunderbird/thunde        0    89652    91118   102756 
-------------------------------------------------------------------------------
  118 4                                       40364   594228   653873  1153092 

ดังนั้นPSSเป็นคอลัมน์ที่น่าสนใจที่นี่เพราะมันใช้เวลาร่วมกันของหน่วยความจำเข้าบัญชี
ซึ่งแตกต่างจากRSSมันมีความหมายที่จะเพิ่มขึ้น เราได้รับผลรวม 654Mb สำหรับกระบวนการของผู้ใช้ที่นี่

เอาต์พุตทั่วทั้งระบบบอกเกี่ยวกับส่วนที่เหลือ:

# smem -tw
Area                           Used      Cache   Noncache 
firmware/hardware                 0          0          0 
kernel image                      0          0          0 
kernel dynamic memory        345784     297092      48692 
userspace memory             654056     181076     472980 
free memory                   15828      15828          0 
----------------------------------------------------------
                            1015668     493996     521672 

ดังนั้นRAM 1Gb ทั้งหมด = 654Mb กระบวนการผู้ใช้ + 346Mb เคอร์เนล mem + 16Mb ฟรี
(ให้หรือใช้ไม่กี่ Mb)

โดยรวมประมาณครึ่งหนึ่งของหน่วยความจำใช้สำหรับแคช (494Mb)

คำถามโบนัส : แคชของผู้ใช้คืออะไรเทียบกับเคอร์เนลแคชที่นี่


btw สำหรับการทดลองใช้ด้วยสายตา:

# smem  --pie=name

ป้อนคำอธิบายรูปภาพที่นี่


14

เครื่องมือที่ดีจริงๆคือpmapรายการการใช้หน่วยความจำปัจจุบันสำหรับกระบวนการบางอย่าง:

pmap -d PID

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับมันดู man page man pmapและดูที่20 เครื่องมือการตรวจสอบระบบลินุกซ์ทุก SysAdmin ควรทราบซึ่งรายการเครื่องมือที่ดีฉันมักจะใช้เพื่อรับข้อมูลเกี่ยวกับกล่อง Linux ของฉัน


นั่นเป็นเครื่องมือที่ยอดเยี่ยม แต่ก็ไม่ได้แก้ปัญหาของฉัน ฉันพยายามหาวิธีการตรวจสอบการใช้หน่วยความจำ "จริง" อย่างมีประสิทธิภาพบนเซิร์ฟเวอร์
GoldenNewby

3
@GoldenNewby ไม่มีสิ่งเช่นการใช้หน่วยความจำ "จริง" ของกระบวนการ การใช้หน่วยความจำจริงของระบบคือสิ่งที่freeบอกคุณ
Gilles

pmap -x PIDนอกจากนี้ยังมีคอลัมน์ RSS ซึ่งมักจะมีประโยชน์มากในการเข้าใจว่าผลรวม RSS ของกระบวนการ (เท่าที่สังเกตเช่นผ่านtopมาจาก)
maxschlepzig

10

เปิดใช้งานด้านบนกดhขอความช่วยเหลือจากนั้นfเพื่อเพิ่มฟิลด์ คุณสามารถเพิ่มฟิลด์ต่อไปนี้:

  • RSS จำนวนหน่วยความจำกายภาพที่แอปพลิเคชันใช้
  • CODE จำนวนหน่วยความจำทั้งหมดที่ใช้รหัสปฏิบัติการของกระบวนการ
  • DATA - จำนวนหน่วยความจำทั้งหมด (kb) ที่อุทิศให้กับข้อมูลและสแต็กของกระบวนการ

ระหว่าง 3 สิ่งนี้คุณควรได้ผลลัพธ์ที่แม่นยำ นอกจากนี้คุณยังสามารถใช้ทดแทนรายละเอียดเพิ่มเติมด้านบนผมขอแนะนำให้หรือhtopatop

แก้ไข:เกือบลืมถ้าคุณต้องการข้อมูลรายละเอียดจริง ๆ ค้นหา PID และแมวไฟล์ต่อไปนี้

PID=123

cat /proc/123/status

แก้ไข 2:หากคุณสามารถค้นหาหรือมีหนังสือ:

การปรับประสิทธิภาพของ Linux ให้เหมาะสม: คู่มือปฏิบัติงานสำหรับ Linux Performance Tools

มีส่วนที่ 5: เครื่องมือประสิทธิภาพ: หน่วยความจำเฉพาะกระบวนการ - มีข้อมูลมากกว่าที่คุณต้องการ


ด้านบนโดยค่าเริ่มต้นมีขนาด RSS ของกระบวนการ ด้านบนให้ผลลัพธ์ที่เหมือนกันเช่น "ps aux" ในตัวอย่างของฉัน คำถามของฉันคือว่า RSS ที่รวมกันของกระบวนการทั้งหมดนั้นสูงกว่าการใช้หน่วยความจำ "ที่ใช้งาน" บนเซิร์ฟเวอร์ทั้งหมดอย่างไร
GoldenNewby

5

psให้ปริมาณหน่วยความจำที่ใช้ในแต่ละกระบวนการ หน่วยความจำบางส่วนนั้นเป็นไฟล์ mmapped ซึ่งนับอยู่ในแคช หน่วยความจำบางส่วนนั้น (โดยเฉพาะรหัส) ใช้ร่วมกับกระบวนการอื่นดังนั้นหากคุณเพิ่มค่า RSS ก็จะถูกนับหลายครั้ง

ไม่มีคำตอบที่ถูกต้องเกี่ยวกับ“ กระบวนการนี้ใช้หน่วยความจำเท่าไหร่?” เนื่องจากมันไม่ได้ขึ้นอยู่กับกระบวนการเพียงอย่างเดียว แต่ยังขึ้นอยู่กับสภาพแวดล้อมด้วย มีค่าต่าง ๆ มากมายที่คุณอาจเรียกว่า "การใช้หน่วยความจำ" ของกระบวนการและพวกเขาไม่ตรงกันหรือเพิ่มขึ้นเพราะพวกเขากำลังนับสิ่งที่แตกต่างกัน


4

ในขณะที่คนอื่นชี้ให้เห็นอย่างถูกต้องมันเป็นเรื่องยากที่จะจัดการกับหน่วยความจำจริงที่ใช้โดยกระบวนการสิ่งที่มีพื้นที่ที่ใช้ร่วมกันและไฟล์ mmap'ed และอะไรก็ตาม

หากคุณเป็นผู้ทดลองคุณสามารถเรียกใช้valgrind และเทือกเขา สิ่งนี้อาจจะค่อนข้างหนักสำหรับผู้ใช้ทั่วไป แต่คุณจะได้รับแนวคิดเกี่ยวกับพฤติกรรมความจำของแอปพลิเคชันเมื่อเวลาผ่านไป หากแอปพลิเคชัน malloc () เป็นสิ่งที่ต้องการจริงๆสิ่งนี้จะช่วยให้คุณแสดงการใช้หน่วยความจำแบบไดนามิกที่แท้จริงของกระบวนการ แต่การทดลองนี้สามารถ "วางยาพิษ" ได้

ในการทำให้เรื่องซับซ้อนลีนุกซ์อนุญาตให้คุณเขียนทับหน่วยความจำของคุณมากเกินไป เมื่อคุณใช้หน่วยความจำ malloc () แสดงว่าคุณตั้งใจจะใช้ความจำ แต่การจัดสรรจะไม่เกิดขึ้นจนกว่าคุณจะเขียนไบต์ลงในหน้าใหม่ของ "RAM" ที่จัดสรรของคุณ คุณสามารถพิสูจน์ได้ด้วยตัวเองโดยการเขียนและรันโปรแกรม C ตัวเล็ก ๆ เช่น:

// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    void *p;
    sleep(5)
    p = malloc(16ULL*1024*1024*1024);
    printf("p = %p\n", p);
    sleep(30);
    return 0;
}

# Shell:
cc test.c -o test && ./test &
top -p $!

รันสิ่งนี้บนเครื่องที่มี RAM น้อยกว่า 16GB และ voila! คุณเพิ่งได้คะแนนจากหน่วยความจำ 16GB! (ไม่ไม่ได้จริงๆ)

โปรดสังเกตtopว่าคุณเห็น "VIRT" เป็น 16.004G แต่% MEM คือ 0.0

เรียกใช้อีกครั้งด้วย valgrind:

# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30

และ massif บอกว่า "ผลรวมของ allocs () = 16GB" นั่นไม่น่าสนใจมาก

แต่ถ้าคุณใช้ในกระบวนการมีสติ :

# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30

--------------------------------------------------------------------------------
Command:            cc test.c -o test
Massif arguments:   (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------


    KB
77.33^                                                                       :
     |                                                                      #:
     |                                                                :@::@:#:
     |                                                           :::::@@::@:#:
     |                                                         @:: :::@@::@:#:
     |                                                     ::::@:: :::@@::@:#:
     |                                             ::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                      :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
     |                      :@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |              :@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |          :::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |        :::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
   0 +----------------------------------------------------------------------->Mi
     0                                                                   1.140

และที่นี่เราเห็น (มากสังเกตุและมีความมั่นใจสูงมาก) ว่าคอมไพเลอร์จัดสรรฮีป 77KB

เหตุใดจึงต้องพยายามอย่างหนักเพื่อให้ได้รับการใช้งานฮีพเพียงอย่างเดียว เนื่องจากวัตถุที่ใช้ร่วมกันและส่วนข้อความทั้งหมดที่กระบวนการใช้ (ในตัวอย่างนี้คอมไพเลอร์) ไม่น่าสนใจอย่างมาก ค่าใช้จ่ายคงที่สำหรับกระบวนการ อันที่จริงการขอร้องกระบวนการต่อมาเกือบจะ "ฟรี"

เปรียบเทียบและคอนทราสต์ต่อไปนี้ด้วย:

MMAP () ไฟล์ 1GB VMSize ของคุณจะเป็น 1 + GB แต่คุณจะใช้ขนาดชุดที่อยู่อาศัยจะเป็นเพียงบางส่วนของไฟล์ที่คุณได้รับการทำเพจใน และถ้าคุณ "อ่าน" ไฟล์ทั้งหมดจากนั้นเมื่อถึงจุดสิ้นสุดเคอร์เนลอาจเริ่มต้นเพจแล้ว (ซึ่งเป็นเรื่องง่ายที่จะทำเพราะเคอร์เนลรู้วิธีการ / ตำแหน่งที่จะเปลี่ยนหน้าเหล่านั้นได้อย่างถูกต้อง ) ไม่ว่าในกรณีใด VMSize หรือ RSS จะเป็นตัวบ่งชี้ที่ดีสำหรับการใช้งาน "หน่วยความจำ" ของคุณ คุณยังไม่ได้ malloc () 'ed อะไรเลย

ในทางตรงกันข้าม Malloc () และแตะหน่วยความจำจำนวนมาก - จนกว่าหน่วยความจำของคุณจะถูกเปลี่ยนเป็นดิสก์ ดังนั้นหน่วยความจำที่จัดสรรของคุณจะเกิน RSS ของคุณแล้ว ที่นี่ VMSize ของคุณอาจเริ่มบอกบางสิ่งกับคุณ (กระบวนการของคุณเป็นเจ้าของหน่วยความจำมากกว่าสิ่งที่อยู่ใน RAM จริง) แต่ก็ยังคงยากที่จะแยกแยะความแตกต่างระหว่าง VM ซึ่งเป็นเพจที่ใช้ร่วมกันและ VM ที่เปลี่ยนข้อมูล

นี่คือจุดที่ valgrind / massif ได้รับความสนใจ มันแสดงให้คุณเห็นถึงสิ่งที่คุณจัดสรรไว้โดยไม่เจตนา


ฉันมีคำถามสำหรับคุณ ฉันมีกระบวนการที่ mlock () เป็นไฟล์ mmap'ed ทั้งหมด มีวิธีกำหนดจำนวนหน่วยความจำนี้ที่ถูกใช้งานอย่างแข็งขันหรือไม่จำนวนหน่วยความจำที่ถูกอ่านหรือเขียนเป็นในนาทีสุดท้ายหรือสองนาที?
Michael Martinez

2

ลองสิ่งนี้: มันจะให้ RAM ทั้งหมดที่คุณใช้จริงโดยกระบวนการทั้งหมดที่ทำงานเป็น MB

ps -eo size,pid,user,command --sort -size | awk '
  { hr=$1/1024 ; printf("%13.2f Mb ",hr) } 
  { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }
  ' | awk '{total=total + $1} END {print total}'

sizeรายงานโดยpsมีความสัมพันธ์น้อยมากที่จะใช้หน่วยความจำที่เกิดขึ้นจริง มันเป็นขนาดเสมือนของแต่ละกระบวนการซึ่งไม่จำเป็นต้องจัดสรรหน่วยความจำ นอกจากนี้ยังไม่รวมกลุ่มที่จัดสรร
Matt

-2

มันจะแสดงจำนวนผู้ใช้หน่วยความจำโดยผู้ใช้ ..

#!/bin/bash
total_mem=0

printf "%-10s%-10s\n" User MemUsage

while read u m
do
        [[ $old_user != $u ]] && {  printf "%-10s%-0.1f\n" $old_user $total_mem;
                                    total_mem=0; }
        total_mem="$(echo $m + $total_mem | bc)"
        old_user=$u

done < <(ps --no-headers -eo user,%mem| sort -k1)

#EOF

-3

ใช้คำสั่งนี้เพื่อค้นหาการใช้งานหน่วยความจำใน%

หน่วยความจำที่ใช้:

grep Mem | awk '{print $3/$2 * 100.0}'

หน่วยความจำฟรี

grep Mem | awk '{print $4/$2 * 100.0}'

3
เอ่อนี่จะไม่ทำอะไรเลย grepจะนั่งรอการป้อนข้อมูล
mattdm

1
สิ่งนี้ควรเป็นfree -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.