Java Virtual Machine - GCs รุ่น
JVM ส่วนใหญ่แบ่งกองออกเป็นสามรุ่น - the young generation (YG), the old generation (OG) and permanent generation (also called tenured generation). อะไรคือสาเหตุเบื้องหลังความคิดเช่นนั้น?
การศึกษาเชิงประจักษ์พบว่าวัตถุส่วนใหญ่ที่สร้างขึ้นมีอายุการใช้งานสั้นมาก -
ที่มา
https://www.oracle.com
ดังที่คุณเห็นว่าเมื่อวัตถุมีการจัดสรรเวลามากขึ้นเรื่อย ๆ จำนวนไบต์ที่รอดชีวิตจะน้อยลง (โดยทั่วไป) วัตถุ Java มีอัตราการตายสูง
เราจะดูตัวอย่างง่ายๆ คลาส String ใน Java ไม่เปลี่ยนรูป ซึ่งหมายความว่าทุกครั้งที่คุณต้องเปลี่ยนเนื้อหาของอ็อบเจกต์ String คุณต้องสร้างอ็อบเจกต์ใหม่ทั้งหมด ให้เราสมมติว่าคุณทำการเปลี่ยนแปลงสตริง 1,000 ครั้งในลูปดังที่แสดงในโค้ดด้านล่าง -
String str = “G11 GC”;
for(int i = 0 ; i < 1000; i++) {
str = str + String.valueOf(i);
}
ในแต่ละลูปเราสร้างออบเจ็กต์สตริงใหม่และสตริงที่สร้างขึ้นระหว่างการทำซ้ำก่อนหน้านี้จะไร้ประโยชน์ (นั่นคือไม่ได้อ้างอิงโดยการอ้างอิงใด ๆ ) อายุการใช้งานของวัตถุนั้นเป็นเพียงการวนซ้ำเพียงครั้งเดียว - GC จะถูกรวบรวมในเวลาไม่นาน วัตถุอายุสั้นดังกล่าวจะถูกเก็บไว้ในพื้นที่ของคนรุ่นใหม่ของกอง กระบวนการเก็บรวบรวมสิ่งของจากคนรุ่นใหม่เรียกว่าการเก็บขยะเล็กน้อยและมักจะทำให้โลกหยุดชะงัก
ในขณะที่คนรุ่นใหม่เต็มไปด้วย GC ก็เก็บขยะเล็กน้อย วัตถุที่ตายแล้วจะถูกทิ้งและวัตถุที่มีชีวิตจะถูกย้ายไปยังคนรุ่นเก่า เธรดแอ็พพลิเคชันหยุดในระหว่างกระบวนการนี้
ที่นี่เราจะเห็นข้อดีของการออกแบบรุ่นดังกล่าว คนรุ่นใหม่เป็นเพียงส่วนเล็ก ๆ ของกองและได้รับการเติมเต็มอย่างรวดเร็ว แต่การประมวลผลจะใช้เวลาน้อยกว่าเวลาที่ใช้ในการประมวลผลฮีปทั้งหมด ดังนั้นการหยุดชั่วคราว 'stop-theworld' ในกรณีนี้จึงสั้นกว่ามากแม้ว่าจะบ่อยกว่าก็ตาม เราควรตั้งเป้าหมายที่จะหยุดให้สั้นลงมากกว่าการหยุดที่นานกว่าเสมอแม้ว่าอาจจะบ่อยกว่าก็ตาม เราจะพูดถึงเรื่องนี้โดยละเอียดในส่วนต่อไปของบทช่วยสอนนี้
คนรุ่นใหม่แบ่งออกเป็นสองช่อง - eden and survivor space. วัตถุที่รอดชีวิตในระหว่างการสะสมของอีเดนจะถูกย้ายไปยังอวกาศผู้รอดชีวิตและผู้ที่รอดชีวิตจากอวกาศผู้รอดชีวิตจะถูกย้ายไปยังคนรุ่นเก่า คนรุ่นใหม่ถูกบดอัดในขณะที่รวบรวม
เมื่อวัตถุถูกเคลื่อนย้ายไปยังคนรุ่นเก่ามันก็จะเต็มไปด้วยในที่สุดและจะต้องถูกรวบรวมและบดอัด อัลกอริทึมที่แตกต่างกันใช้แนวทางที่แตกต่างกัน บางคนหยุดเธรดของแอปพลิเคชัน (ซึ่งนำไปสู่การหยุด 'หยุดโลก' ที่ยาวนานเนื่องจากคนรุ่นเก่ามีขนาดค่อนข้างใหญ่เมื่อเทียบกับคนรุ่นใหม่) ในขณะที่บางคนทำไปพร้อมกันในขณะที่เธรดแอปพลิเคชันทำงาน กระบวนการนี้เรียกว่า GC เต็มรูปแบบ นักสะสมสองคนดังกล่าวคือCMS and G1.
ตอนนี้ให้เราวิเคราะห์อัลกอริทึมเหล่านี้โดยละเอียด
GC แบบอนุกรม
เป็น GC เริ่มต้นบนเครื่องระดับไคลเอนต์ (เครื่องประมวลผลเดี่ยวหรือ 32b JVM, Windows) โดยทั่วไปแล้ว GC จะมีการทำงานแบบมัลติเธรดเป็นจำนวนมาก แต่ GC แบบอนุกรมไม่ใช่ มีเธรดเดียวในการประมวลผลฮีปและจะหยุดเธรดแอ็พพลิเคชันเมื่อใดก็ตามที่มีการทำ GC รองหรือ GC หลัก เราสามารถสั่งให้ JVM ใช้ GC นี้ได้โดยระบุแฟล็ก:-XX:+UseSerialGC. หากเราต้องการให้ใช้อัลกอริทึมที่แตกต่างกันให้ระบุชื่ออัลกอริทึม โปรดทราบว่าคนรุ่นเก่าถูกบีบอัดอย่างเต็มที่ในช่วง GC ที่สำคัญ
ปริมาณงาน GC
GC นี้เป็นค่าเริ่มต้นบน JVM 64b และเครื่องหลาย CPU ไม่เหมือนกับ GC แบบอนุกรมคือใช้เธรดหลายชุดในการประมวลผลคนรุ่นใหม่และรุ่นเก่า ด้วยเหตุนี้ GC จึงเรียกอีกอย่างว่าparallel collector. เราสามารถสั่งให้ JVM ของเราใช้ตัวรวบรวมนี้โดยใช้แฟล็ก:-XX:+UseParallelOldGC หรือ -XX:+UseParallelGC(สำหรับ JDK 8 เป็นต้นไป) เธรดของแอ็พพลิเคชันหยุดทำงานในขณะที่ทำการรวบรวมขยะหลักหรือรอง เช่นเดียวกับตัวสะสมอนุกรมมันกระชับคนรุ่นใหม่ในช่วง GC ที่สำคัญ
ทรูพุต GC รวบรวม YG และ OG เมื่อ eden เต็มแล้วตัวเก็บรวบรวมจะขับอ็อบเจ็กต์ที่มีชีวิตออกจากมันลงใน OG หรือช่องว่างผู้รอดชีวิต (SS0 และ SS1 ในแผนภาพด้านล่าง) วัตถุที่ตายแล้วจะถูกทิ้งเพื่อเพิ่มพื้นที่ว่างที่พวกเขาครอบครอง
ก่อน GC ของ YG
หลังจาก GC ของ YG
ในระหว่าง GC เต็มตัวรวบรวมทรูพุตจะล้าง YG, SS0 และ SS1 ทั้งหมด หลังจากการดำเนินการ OG จะมีเฉพาะวัตถุที่มีชีวิตเท่านั้น เราควรสังเกตว่าตัวรวบรวมทั้งสองตัวข้างต้นหยุดเธรดของแอปพลิเคชันในขณะที่ประมวลผลฮีป ซึ่งหมายความว่า 'โลกหยุดยาว' หยุดชั่วคราวในช่วง GC ที่สำคัญ สองอัลกอริทึมถัดไปมีเป้าหมายที่จะกำจัดพวกมันโดยต้องเสียทรัพยากรฮาร์ดแวร์มากขึ้น -
นักสะสม CMS
ย่อมาจาก 'มาร์คกวาดพร้อมกัน' หน้าที่ของมันคือใช้เธรดพื้นหลังเพื่อสแกนผ่านคนรุ่นเก่าเป็นระยะ ๆ และกำจัดวัตถุที่ตายแล้ว แต่ในช่วงที่มี GC เล็กน้อยเธรดของแอปพลิเคชันจะหยุดทำงาน อย่างไรก็ตามการหยุดชั่วคราวมีค่อนข้างน้อย สิ่งนี้ทำให้ CMS เป็นตัวรวบรวมการหยุดชั่วคราวต่ำ
ตัวรวบรวมนี้ต้องการเวลา CPU เพิ่มเติมเพื่อสแกนผ่านฮีปขณะรันเธรดแอ็พพลิเคชัน นอกจากนี้เธรดพื้นหลังจะรวบรวมฮีปและไม่ทำการบดอัดใด ๆ อาจทำให้กองกลายเป็นกระจัดกระจาย เมื่อผ่านไประยะหนึ่ง CMS จะหยุดเธรดแอปพลิเคชันทั้งหมดและกระชับฮีปโดยใช้เธรดเดียว ใช้อาร์กิวเมนต์ JVM ต่อไปนี้เพื่อบอกให้ JVM ใช้ตัวรวบรวม CMS -
“XX:+UseConcMarkSweepGC -XX:+UseParNewGC” เป็นอาร์กิวเมนต์ JVM เพื่อบอกให้ใช้ตัวรวบรวม CMS
ก่อน GC
หลังจาก GC
โปรดทราบว่ากำลังดำเนินการรวบรวมพร้อมกัน
G1 GC
อัลกอริทึมนี้ทำงานโดยการแบ่งฮีปออกเป็นหลายภูมิภาค เช่นเดียวกับตัวรวบรวม CMS จะหยุดเธรดของแอ็พพลิเคชันในขณะที่ทำ GC รองและใช้เธรดพื้นหลังเพื่อประมวลผลรุ่นเก่าในขณะที่ยังคงเธรดของแอ็พพลิเคชันไว้ เนื่องจากมีการแบ่งคนรุ่นเก่าออกเป็นภูมิภาคจึงทำให้กระชับขณะเคลื่อนย้ายสิ่งของจากภูมิภาคหนึ่งไปยังอีกภูมิภาคหนึ่ง ดังนั้นการแยกส่วนจึงต่ำที่สุด คุณสามารถใช้แฟล็ก:XX:+UseG1GCเพื่อบอกให้ JVM ของคุณใช้อัลกอริทึมนี้ เช่นเดียวกับ CMS ก็ต้องใช้เวลา CPU มากขึ้นในการประมวลผลฮีปและรันเธรดแอปพลิเคชันพร้อมกัน
อัลกอริทึมนี้ได้รับการออกแบบมาเพื่อประมวลผลฮีปที่ใหญ่ขึ้น (> 4G) ซึ่งแบ่งออกเป็นภูมิภาคต่างๆ ภูมิภาคเหล่านั้นบางส่วนประกอบด้วยคนรุ่นใหม่และส่วนที่เหลือประกอบด้วยคนรุ่นเก่า YG ถูกล้างโดยใช้แบบดั้งเดิม - เธรดแอปพลิเคชันทั้งหมดจะหยุดลงและวัตถุทั้งหมดที่ยังมีชีวิตอยู่สำหรับคนรุ่นเก่าหรือพื้นที่ผู้รอดชีวิต
โปรดทราบว่าอัลกอริทึม GC ทั้งหมดแบ่งฮีปออกเป็น YG และ OG และใช้ STWP เพื่อล้าง YG กระบวนการนี้มักจะเร็วมาก