ฉันบังเอิญค้นพบคำจำกัดความของ "หมูในงูหลาม (หมายเหตุ: มันเหมือนกับงูที่โลภและไม่เพียงพอกลืนช้าง)" ในภาษาจีนเมื่อฉันดูอภิธานศัพท์การจัดการหน่วยความจำ ดังนั้นฉันจึงเกิดบทความนี้ขึ้น หากดูเผินๆ คำนี้หมายถึง GC ส่งเสริมวัตถุขนาดใหญ่จากรุ่นสู่รุ่นอย่างต่อเนื่อง การทำเช่นนี้ก็เหมือนกับงูหลามกลืนเหยื่อทั้งหมดจนไม่สามารถเคลื่อนไหวได้ในขณะที่ย่อย
ตลอด 24 ชั่วโมงต่อมา จิตใจของฉันก็เต็มไปด้วยภาพงูเหลือมที่หายใจไม่ออกตัวนี้ซึ่งฉันไม่สามารถกำจัดออกไปได้ ดังที่จิตแพทย์กล่าวไว้ วิธีที่ดีที่สุดในการบรรเทาความกลัวคือการพูดออกมา ดังนั้นบทความนี้ แต่เรื่องต่อไปที่เราอยากพูดถึงไม่ใช่ python แต่เป็นการปรับแต่ง GC ฉันสาบานต่อพระเจ้า
ทุกคนรู้ดีว่าการหยุดชั่วคราวของ GC อาจทำให้เกิดปัญหาคอขวดด้านประสิทธิภาพได้อย่างง่ายดาย JVM สมัยใหม่มาพร้อมกับตัวรวบรวมขยะขั้นสูงเมื่อปล่อยออกมา แต่จากประสบการณ์ของฉัน การค้นหาการกำหนดค่าที่เหมาะสมที่สุดสำหรับแอปพลิเคชันบางตัวเป็นเรื่องยากมาก การปรับด้วยตนเองอาจยังมีความหวังริบหรี่ แต่คุณต้องเข้าใจกลไกที่แน่นอนของอัลกอริทึม GC ในเรื่องนี้ บทความนี้จะเป็นประโยชน์กับคุณ ด้านล่างนี้ ฉันจะใช้ตัวอย่างเพื่ออธิบายว่าการเปลี่ยนแปลงเล็กน้อยในการกำหนดค่า JVM ส่งผลต่อปริมาณงานของแอปพลิเคชันของคุณอย่างไร
ตัวอย่าง
แอปพลิเคชันที่เราใช้สาธิตผลกระทบของ GC ต่อปริมาณงานเป็นโปรแกรมง่ายๆ ประกอบด้วยสองหัวข้อ:
PigEater มันจะเลียนแบบกระบวนการของงูเหลือมยักษ์กินหมูอ้วนตัวใหญ่ รหัสทำได้โดยเพิ่มไบต์ 32MB ลงใน java.util.List และพักเป็นเวลา 100 มิลลิวินาทีหลังจากการกลืนแต่ละครั้ง
PigDgester จำลองกระบวนการย่อยอาหารแบบอะซิงโครนัส รหัสที่ใช้การย่อยอาหารเพียงแค่กำหนดรายชื่อสุกรให้ว่างเปล่า เนื่องจากนี่เป็นกระบวนการที่น่าเบื่อ เธรดนี้จะเข้าสู่โหมดสลีปเป็นเวลา 2,000 มิลลิวินาทีในแต่ละครั้งหลังจากล้างข้อมูลอ้างอิงแล้ว
ทั้งสองเส้นจะทำงานเป็นวงในขณะที่กินและย่อยจนงูอิ่ม จะต้องกินหมูประมาณ 5,000 ตัว
คัดลอกรหัสรหัสดังต่อไปนี้:
แพ็คเกจ eu.plumbr.demo;
PigInThePython คลาสสาธารณะ {
สุกรรายการผันผวนคงที่ = ใหม่ ArrayList ();
int หมูคงที่ผันผวนEaten = 0;
int สุดท้ายคงที่ ENOUGH_PIGS = 5,000;
โมฆะคงสาธารณะ main (String [] args) พ่น InterruptedException {
ใหม่ PigEater().start();
ใหม่ PigDigester().start();
-
PigEater คลาสคงที่ขยายเธรด {
@แทนที่
โมฆะสาธารณะวิ่ง () {
ในขณะที่ (จริง) {
pigs.add (ไบต์ใหม่ [32 * 1024 * 1024]); //32MB ต่อหมู
ถ้า (pigsEaten > ENOUGH_PIGS) กลับมา;
เอาเอแนป(100);
-
-
-
PigDigester คลาสคงที่ขยายเธรด {
@แทนที่
โมฆะสาธารณะวิ่ง () {
เริ่มต้นนาน = System.currentTimeMillis();
ในขณะที่ (จริง) {
เทคเอแนป(2000);
pigsEaten+=pigs.size();
หมู = ArrayList ใหม่ ();
ถ้า (pigsEaten > ENOUGH_PIGS) {
System.out.format("หมูย่อย %d ตัวใน %d ms.%n",pigsEaten, System.currentTimeMillis()-start);
กลับ;
-
-
-
-
โมฆะคง takeANAp (int ms) {
พยายาม {
Thread.sleep(มิลลิวินาที);
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
-
-
ตอนนี้เรากำหนดปริมาณงานของระบบนี้เป็น "จำนวนสุกรที่สามารถย่อยได้ต่อวินาที" เมื่อพิจารณาว่าหมูถูกยัดเข้าไปในงูหลามนี้ทุกๆ 100 มิลลิวินาที เราจะเห็นได้ว่าปริมาณงานสูงสุดตามทฤษฎีของระบบนี้สามารถเข้าถึง 10 พิก/วินาที
ตัวอย่างการกำหนดค่า GC
มาดูประสิทธิภาพของการใช้ระบบการกำหนดค่าที่แตกต่างกันสองระบบกัน แอปพลิเคชันจะทำงานบน Mac แบบดูอัลคอร์ (OS X10.9.3) พร้อม RAM ขนาด 8GB โดยไม่คำนึงถึงการกำหนดค่า
การกำหนดค่าครั้งแรก:
ฮีป 1.4G (-Xms4g -Xmx4g)
2. ใช้ CMS เพื่อล้างข้อมูลรุ่นเก่า (-XX:+UseConcMarkSweepGC) และใช้ตัวรวบรวมแบบขนานเพื่อล้างข้อมูลรุ่นใหม่ (-XX:+UseParNewGC)
3. จัดสรรฮีป 12.5% (-Xmn512m) ให้กับคนรุ่นใหม่ และจำกัดขนาดของพื้นที่อีเดนและพื้นที่ผู้รอดชีวิตให้เท่ากัน
การกำหนดค่าที่สองแตกต่างออกไปเล็กน้อย:
ฮีป 1.2G (-Xms2g -Xms2g)
2. ทั้งรุ่นใหม่และรุ่นเก่าใช้ Parellel GC (-XX:+UseParallelGC)
3. จัดสรรฮีป 75% ให้กับคนรุ่นใหม่ (-Xmn 1536m)
4. ตอนนี้ถึงเวลาเดิมพันแล้ว การกำหนดค่าใดจะทำงานได้ดีกว่า (จำไว้ว่าสามารถกินหมูได้กี่ตัวต่อวินาที) ใครก็ตามที่ใส่ชิปไว้ในการกำหนดค่าครั้งแรก คุณจะต้องผิดหวัง ผลลัพธ์ก็ตรงกันข้าม:
1. การกำหนดค่าครั้งแรก (กองใหญ่, รุ่นเก่าขนาดใหญ่, CMS GC) สามารถกินหมูได้ 8.2 ต่อวินาที
2. การกำหนดค่าที่สอง (ฮีปเล็ก, รุ่นใหม่ขนาดใหญ่, Parellel GC) สามารถกินหมูได้ 9.2 ต่อวินาที
ตอนนี้เรามาดูผลลัพธ์นี้อย่างเป็นกลาง ทรัพยากรที่จัดสรรน้อยกว่า 2 เท่า แต่ปริมาณงานเพิ่มขึ้น 12% สิ่งนี้ขัดแย้งกับสามัญสำนึก ดังนั้นจึงจำเป็นต้องวิเคราะห์เพิ่มเติมว่าเกิดอะไรขึ้น
วิเคราะห์ผลลัพธ์ของ GC
เหตุผลนั้นไม่ซับซ้อนจริงๆ คุณสามารถค้นหาคำตอบได้ด้วยการดูสิ่งที่ GC กำลังทำการทดสอบให้ละเอียดยิ่งขึ้น นี่คือที่ที่คุณเลือกเครื่องมือที่คุณต้องการใช้ ด้วยความช่วยเหลือของ jstat ฉันค้นพบความลับเบื้องหลังคำสั่งอาจเป็นดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
jstat -gc -t -h20 PID 1 วินาที
เมื่อวิเคราะห์ข้อมูล ฉันสังเกตเห็นว่าการกำหนดค่า 1 ผ่าน 1129 GC รอบ (YGCT_FGCT) ใช้เวลาทั้งหมด 63.723 วินาที:
คัดลอกรหัสรหัสดังต่อไปนี้:
การประทับเวลา S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
594.0 174720.0 174720.0 163844.1 0.0 174848.0 131074.1 3670016.0 2621693.5 21248.0 2580.9 1006 63.182 116 0.236 63.419
595.0 174720.0 174720.0 163842.1 0.0 174848.0 65538.0 3670016.0 3047677.9 21248.0 2580.9 1008 63.310 117 0.236 63.546
596.1 174720.0 174720.0 98308.0 163842.1 174848.0 163844.2 3670016.0 491772.9 21248.0 2580.9 1,010 63.354 118 0.240 63.595
597.0 174720.0 174720.0 0.0 163840.1 174848.0 131074.1 3670016.0 688380.1 21248.0 2580.9 1,011 63.482 118 0.240 63.723
การกำหนดค่าที่สองหยุดชั่วคราวทั้งหมด 168 ครั้ง (YGCT+FGCT) และใช้เวลาเพียง 11.409 วินาทีเท่านั้น
คัดลอกรหัสรหัสดังต่อไปนี้:
การประทับเวลา S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
539.3 164352.0 164352.0 0.0 0.0 1211904.0 98306.0 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
540.3 164352.0 164352.0 0.0 0.0 1211904.0 425986.2 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
541.4 164352.0 164352.0 0.0 0.0 1211904.0 720900.4 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
542.3 164352.0 164352.0 0.0 0.0 1211904.0 1015812.6 524288.0 164352.2 21504.0 2579.2 27 2.969 141 8.441 11.409
เมื่อพิจารณาว่าภาระงานทั้งสองกรณีเท่ากัน ดังนั้น ในการทดลองกินหมูครั้งนี้ เมื่อ GC ไม่พบวัตถุที่มีอายุยืนยาวก็สามารถทำความสะอาดวัตถุขยะได้เร็วขึ้น ในการกำหนดค่าครั้งแรก ความถี่ของการทำงานของ GC จะอยู่ที่ประมาณ 6 ถึง 7 ครั้ง และเวลาหยุดชั่วคราวทั้งหมดจะอยู่ที่ 5 ถึง 6 ครั้ง
การเล่าเรื่องนี้มีจุดประสงค์สองประการ ก่อนอื่นและที่สำคัญที่สุด ฉันอยากจะกำจัดงูเหลือมที่ชักกระตุกนี้ออกไปจากความคิดของฉัน ข้อดีอีกอย่างที่เห็นได้ชัดกว่าก็คือการปรับแต่ง GC เป็นประสบการณ์ที่ต้องใช้ทักษะมากและคุณต้องมีความเข้าใจแนวคิดพื้นฐานอย่างถ่องแท้ แม้ว่าสิ่งที่ใช้ในบทความนี้เป็นเพียงแอปพลิเคชันทั่วไป แต่ผลลัพธ์ที่แตกต่างกันของการเลือกจะมีผลกระทบอย่างมากต่อปริมาณงานและการวางแผนกำลังการผลิตของคุณ ในการใช้งานในชีวิตจริง ความแตกต่างนี้จะยิ่งใหญ่ยิ่งขึ้น ดังนั้น ขึ้นอยู่กับคุณแล้ว คุณสามารถเชี่ยวชาญแนวคิดเหล่านี้ได้ หรือคุณสามารถมุ่งเน้นไปที่งานประจำวันของคุณและปล่อยให้ Plumbr คิดการกำหนดค่า GC ที่เหมาะสมที่สุดสำหรับความต้องการของคุณ