Java Virtual Machine - การปรับ GC
ในบทที่แล้วเราได้เรียนรู้เกี่ยวกับ Generational Gcs ต่างๆ ในบทนี้เราจะพูดถึงวิธีการปรับ GC
ขนาดกอง
ขนาดฮีปเป็นปัจจัยสำคัญในการทำงานของแอปพลิเคชัน Java ของเรา หากมีขนาดเล็กเกินไปก็จะได้รับการเติมบ่อยและเป็นผลให้ GC ต้องรวบรวมบ่อยๆ ในทางกลับกันถ้าเราเพิ่มขนาดของฮีปแม้ว่าจะต้องรวบรวมน้อยลงความยาวของการหยุดชั่วคราวก็จะเพิ่มขึ้น
นอกจากนี้การเพิ่มขนาดฮีปยังมีโทษรุนแรงต่อระบบปฏิบัติการพื้นฐาน การใช้การเพจระบบปฏิบัติการทำให้โปรแกรมแอปพลิเคชันของเราเห็นหน่วยความจำมากกว่าที่มีอยู่จริง ระบบปฏิบัติการจัดการสิ่งนี้โดยใช้พื้นที่ swap บางส่วนบนดิสก์คัดลอกส่วนที่ไม่ใช้งานของโปรแกรมลงในนั้น เมื่อจำเป็นต้องใช้ระบบปฏิบัติการจะคัดลอกกลับจากดิสก์ไปยังหน่วยความจำ
สมมติว่าเครื่องมีหน่วยความจำ 8G และ JVM เห็นหน่วยความจำเสมือน 16G JVM จะไม่ทราบว่าในระบบมีเพียง 8G เท่านั้น มันจะขอ 16G จาก OS และเมื่อได้รับหน่วยความจำนั้นก็จะใช้งานต่อไป ระบบปฏิบัติการจะต้องสลับข้อมูลจำนวนมากเข้าและออกและนี่เป็นโทษประสิทธิภาพอย่างมากในระบบ
จากนั้นการหยุดชั่วคราวซึ่งจะเกิดขึ้นระหว่าง GC เต็มของหน่วยความจำเสมือนดังกล่าว เนื่องจาก GC จะทำหน้าที่ในฮีปทั้งหมดสำหรับการรวบรวมและการบดอัดจึงต้องรอนานมากกว่าที่หน่วยความจำเสมือนจะถูกสลับออกจากดิสก์ ในกรณีของตัวรวบรวมพร้อมกันเธรดพื้นหลังจะต้องรอเป็นจำนวนมากเพื่อที่จะคัดลอกข้อมูลจากพื้นที่สวอปไปยังหน่วยความจำ
ดังนั้นคำถามที่ว่าเราควรตัดสินใจอย่างไรเกี่ยวกับขนาดฮีปที่เหมาะสมที่สุด กฎข้อแรกคือห้ามขอให้ระบบปฏิบัติการมีหน่วยความจำมากกว่าที่มีอยู่จริง วิธีนี้จะช่วยป้องกันปัญหาในการแลกเปลี่ยนบ่อยๆ หากเครื่องมีการติดตั้งและเรียกใช้ JVM หลายรายการคำขอหน่วยความจำทั้งหมดที่รวมกันทั้งหมดจะน้อยกว่า RAM จริงที่มีอยู่ในระบบ
คุณสามารถควบคุมขนาดของการร้องขอหน่วยความจำโดย JVM โดยใช้สองแฟล็ก -
-XmsN - ควบคุมหน่วยความจำเริ่มต้นที่ร้องขอ
-XmxN - ควบคุมหน่วยความจำสูงสุดที่สามารถร้องขอได้
ค่าดีฟอลต์ของแฟล็กทั้งสองนี้ขึ้นอยู่กับระบบปฏิบัติการพื้นฐาน ตัวอย่างเช่นสำหรับ JVM 64b ที่ทำงานบน MacOS, -XmsN = 64M และ -XmxN = ขั้นต่ำ 1G หรือ 1 ใน 4 ของหน่วยความจำฟิสิคัลทั้งหมด
โปรดทราบว่า JVM สามารถปรับระหว่างสองค่าโดยอัตโนมัติ ตัวอย่างเช่นหากสังเกตเห็นว่ามี GC เกิดขึ้นมากเกินไปก็จะเพิ่มขนาดหน่วยความจำต่อไปตราบเท่าที่มีขนาดต่ำกว่า -XmxN และบรรลุเป้าหมายประสิทธิภาพที่ต้องการ
หากคุณทราบว่าแอปพลิเคชันของคุณต้องการหน่วยความจำเท่าใดคุณสามารถตั้งค่า -XmsN = -XmxN ในกรณีนี้ JVM ไม่จำเป็นต้องหาค่า "ที่เหมาะสม" ของฮีปดังนั้นกระบวนการ GC จึงมีประสิทธิภาพมากขึ้นเล็กน้อย
ขนาดรุ่น
คุณสามารถตัดสินใจได้ว่าคุณต้องการจัดสรรฮีปจำนวนเท่าใดให้กับ YG และจำนวนเท่าใดที่คุณต้องการจัดสรรให้กับ OG ค่าทั้งสองนี้มีผลต่อประสิทธิภาพของแอปพลิเคชันของเราในลักษณะต่อไปนี้
ถ้าขนาดของ YG ใหญ่มากก็จะมีการรวบรวมน้อยลง ซึ่งจะส่งผลให้มีการเลื่อนระดับวัตถุไปยัง OG น้อยลง ในทางกลับกันหากคุณเพิ่มขนาดของ OG มากเกินไปการรวบรวมและบีบอัดจะใช้เวลามากเกินไปและอาจทำให้หยุด STW ได้นาน ดังนั้นผู้ใช้ต้องหาจุดสมดุลระหว่างสองค่านี้
ด้านล่างนี้คือแฟล็กที่คุณสามารถใช้เพื่อตั้งค่าเหล่านี้ -
-XX:NewRatio=N: อัตราส่วนของ YG ต่อ OG (ค่าเริ่มต้น = 2)
-XX:NewSize=N: ขนาดเริ่มต้นของ YG
-XX:MaxNewSize=N: ขนาดสูงสุดของ YG
-XmnN: ตั้งค่า NewSize และ MaxNewSize เป็นค่าเดียวกันโดยใช้แฟล็กนี้
ขนาดเริ่มต้นของ YG ถูกกำหนดโดยค่าของ NewRatio ตามสูตรที่กำหนด -
(total heap size) / (newRatio + 1)
เนื่องจากค่าเริ่มต้นของ newRatio คือ 2 สูตรข้างต้นจึงให้ค่าเริ่มต้นของ YG เท่ากับ 1/3 ของขนาดฮีปทั้งหมด คุณสามารถแทนที่ค่านี้ได้ตลอดเวลาโดยระบุขนาดของ YG อย่างชัดเจนโดยใช้แฟล็ก NewSize แฟล็กนี้ไม่มีค่าเริ่มต้นใด ๆ และหากไม่ได้ตั้งค่าไว้อย่างชัดเจนขนาดของ YG จะคำนวณต่อไปโดยใช้สูตรด้านบน
Permagen และ Metaspace
Permagen และ metaspace เป็นพื้นที่ฮีปที่ JVM เก็บข้อมูลเมตาของคลาส ช่องว่างนี้เรียกว่า 'permagen' ใน Java 7 และใน Java 8 เรียกว่า 'metaspace' ข้อมูลนี้ถูกใช้โดยคอมไพลเลอร์และรันไทม์
คุณสามารถควบคุมขนาดของ Permagen โดยใช้แฟล็กต่อไปนี้: -XX: PermSize=N และ -XX:MaxPermSize=N. ขนาดของ Metaspace สามารถควบคุมได้โดยใช้:-XX:Metaspace- Size=N และ -XX:MaxMetaspaceSize=N.
มีความแตกต่างบางประการในการจัดการ permagen และ metaspace เมื่อไม่ได้ตั้งค่าแฟล็ก ตามค่าเริ่มต้นทั้งสองมีขนาดเริ่มต้นเริ่มต้น แต่ในขณะที่ metaspace สามารถครอบครองฮีปได้มากเท่าที่จำเป็น แต่ Permagen สามารถครอบครองได้ไม่เกินค่าเริ่มต้นเริ่มต้น ตัวอย่างเช่น 64b JVM มีพื้นที่ฮีพ 82M เป็นขนาดของเปอร์มาเจนสูงสุด
โปรดทราบว่าเนื่องจาก metaspace สามารถใช้หน่วยความจำได้ไม่ จำกัด จำนวนเว้นแต่จะระบุว่าไม่เป็นเช่นนั้นอาจเกิดข้อผิดพลาดของหน่วยความจำ GC เต็มจะเกิดขึ้นเมื่อใดก็ตามที่มีการปรับขนาดภูมิภาคเหล่านี้ ดังนั้นในระหว่างการเริ่มต้นหากมีการโหลดคลาสจำนวนมาก metaspace สามารถปรับขนาดได้เรื่อย ๆ ส่งผลให้ GC เต็มทุกครั้ง ดังนั้นจึงต้องใช้เวลานานสำหรับแอปพลิเคชันขนาดใหญ่ในการเริ่มต้นในกรณีที่ขนาด metaspace เริ่มต้นต่ำเกินไป เป็นความคิดที่ดีที่จะเพิ่มขนาดเริ่มต้นเนื่องจากจะช่วยลดเวลาในการเริ่มต้นระบบ
แม้ว่า Permagen และ metaspace จะเก็บข้อมูลเมตาของคลาสไว้ แต่ก็ไม่ถาวรและ GC จะเรียกคืนช่องว่างเช่นเดียวกับในกรณีของวัตถุ โดยทั่วไปจะเป็นกรณีของเซิร์ฟเวอร์แอปพลิเคชัน เมื่อใดก็ตามที่คุณทำการปรับใช้ใหม่กับเซิร์ฟเวอร์ข้อมูลเมตาเก่าจะต้องได้รับการล้างข้อมูลเนื่องจากตัวโหลดคลาสใหม่จะต้องใช้พื้นที่ พื้นที่นี้เป็นอิสระโดย GC