java heap memory หลายคนที่พัฒนาโปรแกรมด้วยภาษา java คงเคยเจอ การจัดสรรทรัพยากรที่ไม่ได้ประสิทธิภาพ แล้วต้องทำไงละถึงจะใช้ได้คุ้มค่า และตอบสนองได้สูงสุด เพื่อให้เข้าใจการทำงานของ jvm วันนี้จะพามาดูถึง jvm ควร config ค่ายังไง เพื่อให้ระบบทำงานได้เต็มประสิทธิภาพ
ตัวอย่างค่า Config JVM จาก RAM 64GB และการทำงานของ JVM
jvmargs { maxMetaspace=[ "-XX:MaxMetaspaceSize=16384M" ] xms=[ "-Xms16384M" ] xmx=[ "-Xmx49152M" ] gc=[ "-XX:+UseConcMarkSweepGC", "-XX:+CMSIncrementalMode" ] }
จากค่าตัวอย่างจะเห็นว่าการใช้ xmx จะใช้ได้ประมาณ 75% ของ RAM ทั้งหมด 64 GB
คำถามแล้วที่เหลือไปไหนละ ? เอาไว้ให้ system running ใช้ไง เช่น OS
MaxMetaspaceSize เป็นตัวกำหนดค่าการจองเนื้อที่ในหน่วยความจำสำหรับ Metaspace ใน Java Virtual Machine (JVM)
Metaspace เป็นพื้นที่ที่ JVM ใช้เพื่อจัดเก็บข้อมูลการนำเข้าคลาส (class metadata) ที่ต้องการสำหรับการทำงานของโปรแกรม Java. มันมีประโยชน์ในการควบคุมจำนวนคลาสที่สามารถถูกโหลดได้ใน JVM และสามารถช่วยป้องกันการใช้งานความจำแบบไม่อั้นเนื่องจากการโหลดคลาสเกินจำนวน
ในตัวอย่างเราใช้, MaxMetaspaceSize=16384M หมายความว่า JVM จะจองเนื้อที่ในหน่วยความจำสูงสุด 16,384 megabytes (หรือ 16 gigabytes) สำหรับ Metaspace. หาก Metaspace ต้องการเพิ่มขนาดอีกและถึงขีดจำกัดนี้, JVM จะทำการเก็บกวาด (Garbage Collect) เพื่อพยายามปล่อยพื้นที่. ถ้าก็ยังไม่พอ, JVM จะส่งข้อผิดพลาด OutOfMemoryError
โปรดทราบว่า Metaspace ใน Java 8 และเวอร์ชันถัดไปแทนที่คลาส Permanent Generation (PermGen) ที่ใช้ใน Java 7 และเวอร์ชันก่อนหน้า
-Xms และ -Xmx เป็นตัวเลือกการกำหนดค่าความจำสำหรับ Java Virtual Machine (JVM). ในคำสั่งรัน Java, คุณสามารถใช้พารามิเตอร์เหล่านี้เพื่อกำหนดขนาดของ heap memory ที่จะใช้งาน
Heap memory ใช้สำหรับการจัดเก็บข้อมูลวัตถุและสิ่งที่สร้างขึ้นด้วยคำสั่ง new ในภาษา Java. ขนาดของ heap สามารถขยายและลดลงได้ในระหว่างการทำงานของโปรแกรม, แต่จะไม่เกินขนาดที่กำหนดด้วย -Xmx. ถ้า heap memory เต็ม และไม่สามารถขยายได้เพิ่ม, JVM จะส่งข้อผิดพลาด OutOfMemoryError
การตั้งค่า -Xms และ -Xmx มีผลต่อประสิทธิภาพของโปรแกรม Java. หากขนาด heap ต่ำเกินไป, จะทำให้มีการเก็บกวาดความจำ (garbage collection) เกิดขึ้นบ่อยเกินควร ทำให้ประสิทธิภาพลดลง. แต่หากขนาด heap สูงเกินไป, การเก็บกวาดความจำจะใช้เวลานาน, และอาจทำให้โปรแกรมหยุดการทำงานชั่วขณะ. ดังนั้น, การตั้งค่าเหล่านี้ต้องคำนึงถึงสมดุลระหว่างใช้งานความจำและประสิทธิภาพ
หลังจากที่เราได้รู้การทำงานของ JVM ไปแล้ว ก็อาจจะสงสัยว่าเราสามารถปรับแต่ง JVM ในขณะทำงานได้ไหม ซึ่ง JVM ก็มี option ที่เป็น Standard Options, Non-standard Options และ Advance Option ให้สำหรับปรับแต่งการทำงานดังนี้
Standard Options
เราสามารถใช้คำสั่ง java เพื่อแสดงรายการ option มาตรฐานของ JVM สามารถเลือกใช้งานได้ตามที่ต้องการ โดยที่ option สำคัญดังนี้
-Dproperty=value
เป็นการตั้งค่า property ของระบบ ตัวแปร property เป็น String ที่ไม่มีช่องว่างหลังจาก -D (Define) แทนที่ชื่อของ property และตัวแปร value เป็น String แทนทีค่าของ property ถ้ามีช่องว่างระหว่างคำจะต้องมีเครื่องหมาย “” กำกับ (ตัวอย่างเช่น -Dfoo="foo bar")
-server
เป็นการเลือก Hotspot Server VM ซึ่ง JDK เวอร์ชัน 64bit เท่านั้นที่รองรับ option นี้
-client
เป็นการเลือก Hotspot Client VM ถ้าเป็น JDK เวอร์ชัน 64bit จะไม่รองรับ option นี้ แต่ใช้ Hotspot Server VM แทน
-d32/-d64
เป็นการระบุว่าจะให้ JVM ทำงานในโหมด 32bit หรือ 64Bit แต่โดยค่าเริ่มต้นจะรันแอพพลิเคชันในโหมด 32bit เว้นแต่ระบบ 64bit ถูกใช้งาน ตอนนี้มีเพียง Hotspot VM ที่รองรับ 64bit และถ้าใช้ option -server จะใช้งาน -d64 โดยปริยาย แต่ถ้าใช้ -client จะไม่ใช้งาน -d64
Non-Standard Options
เราสามารถใช้คำสั่ง java -X เพื่อแสดงรายการของ option เฉพาะของ JVM นั้นๆ และ option ที่สำคัญดังนี้
-Xint
เป็นการรันแอพพลิเคชันในโหมด interpreted-only ซึ่งการใช้งาน native code จะถูกปิดการใช้งาน และ bytecode จะถูกประมวลผลด้วย interpreter การใช้งาน JIT เพื่อเพิ่มประสิทธิภาพการประมวลผลจะไม่เห็นผลในโหมดนี้
-Xbootclasspath:path
เป็นการระบุรายการของ directory ที่มีไฟล์ JAR และ ZIP โดยแยกด้วย : เพื่อหาไฟล์คลาส boot loader
-Xloggc:filename
เป็นระบุไฟล์ซึ่งเก็บข้อมูลของ verbose GC event สำหรับ logging โดยที่ข้อมูลจะถูกเขียนไปในไฟล์เหมือนกับที่แสดงใน output ของ -verbose:gc ซึ่ง -Xloggc จะแทนที่ -verbose:gc ถ้าใส่มาในคำสั่งชุดเดียวกัน
-Xmssize
เป็นการระบุค่าเริ่มต้นของขนาดของ Heap (หน่วยเป็น byte) เป็นค่าผลคูลของ 1024 และมากกว่า 1 MB ต่อท้ายด้วยตัวอักษรที่บ่งบอกว่าเป็นหน่วย, k หรือ K เป็นหน่วย kilobyte, m หรือ M เป็นหน่วย megabyte, g หรือ G เป็นหน่วย gigabyte ตัวอย่างต่อไปนี้เป็นการระบุค่า 6 MB
-Xms6291456 -Xms6144k -Xms6m
ถ้าไม่ระบุ option นี้ขนาดเริ่มต้นของ Heap จะเป็นค่าของผลรวมของขนาดที่ allocate สำหรับ old generation และ young generation, -Xms
-Xmxsize
เป็นการระบุค่ามากที่สุดของขนาดของ Heap (หน่วยเป็น byte) ป็นค่าผลคูลของ 1024 และมากกว่า 2 MB ต่อท้ายด้วยตัวอักษรที่บ่งบอกว่าเป็นหน่วย, k หรือ K เป็นหน่วย kilobyte, m หรือ M เป็นหน่วย megabyte, g หรือ G เป็นหน่วย gigabyte ตัวอย่างต่อไปนี้เป็นการระบุค่า 80 MB
-Xmx83886080 -Xmx81920k -Xmx80m
โดยเริ่มต้นจะใช้ค่าที่ถูกเลือกในขณะ runtime ซึ่งเป็นค่าของ system configuration
-Xnoclassgc
เป็นการปิดการทำงานของ Garbage Collection ของคลาส สามารถประหยัดเวลาขอ GC บ้าง ซึ่งทำให้ interrupt สั้นลงในขณะทำงานของแอพพลิเคชัน
Advance Options
นอกจาก Standard Option และ Non-Standard Option แล้วก็ยังมี option อื่นๆ อีกที่เป็นระดับสูง ซึ่งแบบได้ดังนี้
Behavior
-XX:+UseConcMarkSweepGC
สำหรับเปิดใช้งาน CMS Garbage Collection
-XX:+UseParallelGC
สำหรับเปิดใช้งาน Parallel Garbage Collection
-XX:+UseSerialGC
สำหรับเปิดใช้งาน Serial Garbage Collection
-XX:+UseG1GC
สำหรับเปิดใช้งาน G1 Garbage Collection
Performance
-XX:MaxPermSize=size
เป็นการระบุขนาดสูงสุดของ permanent generation space (หน่วยเป็น byte)
-XX:ThreadStackSize=size
เป็นการระบุขนาดของ thread stack (หน่วยเป็น byte)
-XX:+UseStringCache
เปิดใช้งานการ caching ของ commonly allocated strings
-XX:G1HeapRegionSize=size
เป็นการระบุขนาดของ sub-division ของ G1 Heap (หน่วยเป็น byte)
-XX:MaxGCPauseMillis=time
เป็นการระบุเวลานานที่สุดของการหยุดของ Garbage Collection
-XX:MaxNewSize=size
เป็นการระบุขนาดสูงสุดของ Heap สำหรับ young generation
-XX:+AggressiveOpts
เปิดใช้งาน aggressive performance optimization features
-XX:OnError=string
เป็นการระบุคำสั่งให้ทำงานเมื่อมี Error เกิดขึ้น
Debugging
-XX:ErrorFile=filename
เป็นการระบุ path และชื่อไฟล์ของ Error log
-XX:+HeapDumpOnOutOfMemory
เปิดใช้งาน dump ไฟล์ของ Java Heap ไปเป็นไฟล์ใน directory ที่ทำงานอยู่
-XX:+PrintGC
เปิดใช้งานให้แสดง message ของทุกๆ Garbage Collection
-XX:+TraceClassLoading
เปิดใช้งาน tract ของคลาสที่โหลดมาแล้ว
-XX:+PrintClassHistogram
เปิดใช้งานแสดงคลาส instance histogram หลังจาก Ctrl+C