นี่คือโพสต์เก่า แต่ฉันจะยังคงมีเสรีภาพในการวางความคิดของฉันที่นี่
เริ่มต้นจากใต้, ลีนุกซ์จะแบ่งหน่วยความจำออกเป็นหน้า ๆ (โดยทั่วไปคือ 4K ต่อหน้าบนระบบ x86_64) หลังจากนั้นจะสร้างหน่วยความจำเสมือนที่มีการทำแผนที่กับหน่วยความจำกายภาพโดยใช้ MMU (หน่วยจัดการหน่วยความจำ)
กระบวนการได้รับการจัดสรรหน่วยความจำจากพื้นที่หน่วยความจำเสมือนดังนั้นโปรดทราบเมื่อคุณเห็น / proc / meminfo คุณจะเห็น VMalloc * เป็นรายละเอียดหน่วยความจำเสมือน
ให้บอกว่าคุณมีกระบวนการที่ขอหน่วยความจำ (พูด 300MB - เว็บเบราว์เซอร์) กระบวนการนี้จะได้รับการจัดสรร 300MB จากหน่วยความจำเสมือนอย่างไรก็ตามไม่จำเป็นว่าต้องทำการแมปหน่วยความจำ (ที่แมปกับหน่วยความจำกายภาพ) มีแนวคิดของ "Copy on Write" สำหรับการจัดการหน่วยความจำโดยที่หากกระบวนการของคุณใช้หน่วยความจำที่จัดสรรจากหน่วยความจำเสมือนจริง สิ่งนี้ช่วยให้เคอร์เนลทำงานอย่างถูกต้องในสภาพแวดล้อมแบบหลายกระบวนการได้อย่างมีประสิทธิภาพ
แคชคืออะไร
มีการแชร์หน่วยความจำจำนวนมากที่ใช้โดยกระบวนการ ช่วยบอกว่าไลบรารี glibc นั้นถูกใช้โดยกระบวนการเกือบทั้งหมด อะไรคือประเด็นของการเก็บ glibc หลายสำเนาไว้ในหน่วยความจำเมื่อทุกกระบวนการสามารถเข้าถึงตำแหน่งหน่วยความจำเดียวกันและทำงานได้ ทรัพยากรที่ใช้บ่อยดังกล่าวจะถูกเก็บไว้ในแคชเพื่อที่เมื่อกระบวนการต้องการก็สามารถอ้างถึงตำแหน่งหน่วยความจำเดียวกัน ซึ่งจะช่วยในการเร่งกระบวนการเนื่องจากการอ่าน glibc (ฯลฯ ) อีกครั้ง & อีกครั้งจากดิสก์จะใช้เวลานาน
ด้านบนนี้สำหรับไลบรารีที่ใช้ร่วมกันต่อการพูดเช่นเดียวกันก็เป็นจริงสำหรับการอ่านไฟล์เช่นกัน หากคุณอ่านไฟล์ขนาดใหญ่ (ประมาณ 100-200MB) เป็นครั้งแรกมันจะใช้เวลานาน อย่างไรก็ตามเมื่อคุณลองทำแบบเดิมอีกครั้งมันจะเร็วขึ้น ข้อมูลถูกแคชในหน่วยความจำและการอ่านซ้ำไม่ได้ทำสำหรับบล็อกทั้งหมด
บัฟเฟอร์คืออะไร
เท่าที่เกี่ยวข้องกับบัฟเฟอร์เมื่อกระบวนการทำไฟล์ I / O มันอาศัยบัฟเฟอร์ของเคอร์เนลในการเขียนข้อมูลไปยังดิสก์ กระบวนการร้องขอให้เคอร์เนลทำงาน ดังนั้นในนามของกระบวนการเคอร์เนลเขียนข้อมูลลงใน "บัฟเฟอร์" ของมันและบอกกระบวนการที่เขียนเสร็จแล้ว ในลักษณะ async เคอร์เนลจะยังคงซิงค์ข้อมูลนี้ในบัฟเฟอร์ไปยังดิสก์ ด้วยวิธีนี้กระบวนการพึ่งพาเคอร์เนลเพื่อเลือกเวลาที่ถูกต้องในการซิงค์ข้อมูลกับดิสก์และกระบวนการสามารถทำงานต่อไปได้ จำไว้ว่านี่เป็น I / O ทั่วไปที่กระบวนการปกติกำลังทำอยู่ อย่างไรก็ตามกระบวนการพิเศษที่ต้องยืนยันว่า I / O นั้นทำบนดิสก์จริงแล้วสามารถใช้กลไกอื่นเพื่อทำ I / O บนดิสก์ ยูทิลิตี opensource บางส่วนเป็น libaio นอกจากนี้ยังมีวิธีเรียกการซิงค์อย่างชัดเจนกับ FD ที่เปิดในบริบทกระบวนการของคุณ
ความผิดพลาดของหน้าคืออะไร
ลองพิจารณาตัวอย่างเมื่อคุณเริ่มต้นกระบวนการ (พูดกับเว็บเบราว์เซอร์) ซึ่งมีไบนารี่ประมาณ 300MB อย่างไรก็ตามเว็บเบราว์เซอร์ไบนารีที่สมบูรณ์ขนาด 300MB ไม่สามารถทำงานได้ทันที กระบวนการจะย้ายจากฟังก์ชั่นไปยังฟังก์ชั่นในรหัสของมัน ดังที่ได้กล่าวไว้ก่อนหน้านี้หน่วยความจำเสมือนจะถูกใช้งาน 300MB แต่หน่วยความจำกายภาพทั้งหมดไม่ได้ถูกแมปกับหน่วยความจำกายภาพ (RSS - หน่วยความจำภายในจะน้อยกว่าดูผลลัพธ์สูงสุด) เมื่อการเรียกใช้โค้ดถึงจุดที่หน่วยความจำไม่ได้ถูกแมปจริง ๆ แล้วความผิดพลาดของหน้าจะเป็นปัญหา เคอร์เนลจะจับคู่หน่วยความจำนี้กับฟิสิคัลเชื่อมโยงเพจหน่วยความจำกับกระบวนการของคุณ ความผิดพลาดหน้าดังกล่าวเรียกว่า "ข้อผิดพลาดหน้าเล็กน้อย" ในทำนองเดียวกันเมื่อกระบวนการกำลังทำผิดหน้าไฟล์สำคัญของ I / O จะเพิ่มขึ้น
เมื่อใดและทำไม Swap Out เกิดขึ้น?
สถานการณ์ 1:
สอดคล้องกับรายละเอียดข้างต้นให้พิจารณาสถานการณ์เมื่อจำนวนหน่วยความจำที่ดีกลายเป็นแผนที่หน่วยความจำ และตอนนี้กระบวนการเริ่มต้นขึ้นซึ่งต้องใช้หน่วยความจำ เคอร์เนลจะทำการแมปหน่วยความจำบางส่วน อย่างไรก็ตามแรมทางกายภาพมีไม่เพียงพอที่จะแมปหน่วยความจำ ตอนนี้เคอร์เนลจะดูในแคชก่อนมันจะมีเพจหน่วยความจำเก่าที่ไม่ได้ใช้งาน มันจะล้างหน้าเหล่านั้นไปยังพาร์ติชันแยกต่างหาก (เรียกว่า SWAP) เพิ่มหน้าบางหน้าและแม็พเพจที่ว่างกับการร้องขอใหม่ที่จะมาถึง เนื่องจากการเขียนดิสก์ช้ากว่า solid-state RAM มากกระบวนการนี้ใช้เวลานานจึงเห็นว่าการทำงานช้าลง
สถานการณ์ที่ 2:
ให้บอกว่าคุณเห็นหน่วยความจำว่างมากมายในระบบ แม้ว่าคุณจะเห็นว่ามีการแลกเปลี่ยนเกิดขึ้นมากมาย อาจมีปัญหาในการกระจายตัวของหน่วยความจำ พิจารณาโปรเซสซึ่งต้องการหน่วยความจำต่อเนื่อง 50MB จากเคอร์เนล (โปรดทราบว่าต่อเนื่องกัน) เห็นได้ชัดว่าเคอร์เนลจะจัดสรรหน้าแบบสุ่มให้กับกระบวนการที่แตกต่างกันและปลดปล่อยบางส่วน อย่างไรก็ตามเมื่อเราต้องการหน่วยความจำที่ต่อเนื่องกันมันจะต้องมองหาอันที่ทำให้กระบวนการต้องการ หากไม่สามารถรับหน่วยความจำดังกล่าวได้จะต้องทำการสลับออกจากหน้าหน่วยความจำเก่าบางหน้าจากนั้นจึงจัดสรรหน่วยความจำที่ต่อเนื่องกัน แม้ในกรณีเช่นนี้การสลับหน่วยจะเกิดขึ้น การเริ่มต้นเคอร์เนลเวอร์ชัน 2.6 ขึ้นไปปัญหาการแตกแฟรกเมนต์ดังกล่าวลดลงอย่างมาก อย่างไรก็ตามหากระบบทำงานเป็นเวลานานปัญหาดังกล่าวก็ยังคงเกิดขึ้น
ดูตัวอย่างนี้ ( เอาต์พุต vmstat )
2016-10-29 03:55:32 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
2016-10-29 03:55:32 r b swpd free buff cache si so bi bo in cs us sy id wa st
2016-10-30 03:56:04 19 23 2914752 4692144 3344908 12162628 1660 1 8803 12701 4336 37487 14 7 40 38 0
2016-10-30 03:56:34 3 20 2889296 4977580 3345316 12026752 2109 2 8445 14665 4656 36294 12 7 46 34 0
2016-10-30 03:57:04 1 11 3418868 4939716 3347804 11536356 586 4744 2547 9535 3086 24450 6 3 59 33 0 <<<-----
2016-10-30 03:57:34 3 19 3456252 5449884 3348400 11489728 3291 13371 6407 17957 2997 22556 6 4 66 24 0
2016-10-30 03:58:04 7 6 4194500 5663580 3349552 10857424 2407 12240 3824 14560 2295 18237 4 2 65 29 0
2016-10-30 03:58:34 2 16 4203036 5986864 3348908 10838492 4601 16639 7219 18808 2575 21563 6 4 60 31 0
2016-10-30 03:59:04 3 14 4205652 6059196 3348760 10821448 6624 1597 9431 4357 1750 20471 6 2 60 31 0
2016-10-30 03:59:34 2 24 4206968 6053160 3348876 10777216 5221 2067 10106 7377 1731 19161 3 3 62 32 0
2016-10-30 04:00:04 0 13 4205172 6005084 3348932 10785896 6236 1609 10330 6264 1739 20348 4 2 67 26 0
2016-10-30 04:00:34 4 11 4206420 5996396 3348976 10770220 6554 1253 10382 4896 1964 42981 10 5 58 27 0
2016-10-30 04:01:04 6 4 4177176 5878852 3348988 10825840 8682 765 10126 2716 1731 32949 8 4 69 19 0
@ 2016-10-30 03:57:04 เราเห็นว่ายังมีแรมฟรีจำนวนมาก อย่างไรก็ตามแม้จะมีการสลับเกิดขึ้น เราตรวจสอบทรีกระบวนการ ณ จุดนี้และเราไม่เห็นกระบวนการใด ๆ ที่จะเกิดขึ้นซึ่งต้องการหน่วยความจำจำนวนมาก (มากกว่าหน่วยความจำที่ว่าง) ข้อสงสัยที่ชัดเจนคือสถานการณ์ 2 ที่อธิบายไว้ข้างต้น เราตรวจสอบบันทึก buddyinfo และ zoneinfo ด้านบน (ใช้ echo m> / proc / sysrq-trigger เพื่อตรวจสอบสิ่งเหล่านี้เอาต์พุตจะเข้าสู่ syslogs)
สำหรับระบบปกติของเราการเปรียบเทียบข้อมูลโซนจะเป็นไปตามนี้ และกราฟสำหรับแคช / ฟรี / หน่วยความจำต่ำยังกล่าวถึงด้านล่าง
เมื่อดูข้อมูลจะเห็นได้ชัดว่ามีการแตกแฟรกเมนต์ในโหนด 0 และโหนด 1 ปกติ (โหนดเป็นเครื่องที่ใช้ NUMA ดังนั้นจึงมีหลายโหนด (ดู numactl เพื่อตรวจสอบข้อมูลสำหรับระบบของคุณ))
การแตกแฟรกเมนต์ของหน่วยความจำยังเป็นสาเหตุที่ทำให้การใช้ swap เพิ่มขึ้นแม้ว่าหน่วยความจำว่างจะมีอยู่