Java 8 ย้าย **PermGen (Permanent Generation)** ไปเป็น **Metaspace** - การเปลี่ยนแปลงสำคัญใน Memory Management
ตารางเปรียบเทียบ
| ลำดับ | หัวข้อ | PermGen (Java 7 และก่อน) | Metaspace (Java 8+) |
|---|---|---|---|
| 1 | พื้นฐาน | Memory area สำหรับ Class metadata (class definitions, static variables, bytecode, methods) | แทนที่ PermGen - เก็บ Class metadata เช่นเดียวกันแต่ใน Native Memory |
| 2 | Location | ส่วนหนึ่งของ **Heap Memory** | **Native Memory (OS Memory)** - แยกจาก Heap |
| 3 | Default Size | 64 MB (32-bit) / 82 MB (64-bit) | Auto-expand (ไม่มี default max) |
| 4 | Max Size Config | -XX:MaxPermSize=256m | -XX:MaxMetaspaceSize=256m |
| 5 | Initial Size Config | -XX:PermSize=64m | -XX:MetaspaceSize=64m (initial high-water mark) |
| 6 | GC Behavior | Full GC ถ้าเต็ม (ช้า, STW ยาว) | Metaspace GC แยกต่างหาก (เร็วกว่า, concurrent) |
| 7 | Class Unloading | ยาก/นادرة (ต้อง Full GC) | รองรับดีกว่า (Class unloading ทำได้ง่ายขึ้น) |
| 8 | OOM Error | java.lang.OutOfMemoryError: PermGen space | java.lang.OutOfMemoryError: Metaspace |
| 9 | String Interning | String pool อยู่ใน PermGen | String pool ย้ายไป Heap (Java 7+) |
ทำไมต้องเปลี่ยนเป็น Metaspace?
- ✅ **ไม่ต้อง tuning PermSize** - Auto-expand ตามความต้องการ
- ✅ **ไม่มี OOM: PermGen** - เพราะใช้ Native Memory (จำกัดโดย OS/RAM)
- ✅ **Class Unloading ดีกว่า** - เหมาะกับ Dynamic class loading (OSGi, Hot reload, JSP)
- ✅ **แยกจาก Heap** - Heap ใช้สำหรับ Object instances เท่านั้น
- ✅ **Performance** - GC metadata แยกจาก object GC
JVM Flags สำคัญ
| Flag | คำอธิบาย | Default |
|---|---|---|
-XX:MetaspaceSize | Initial high-water mark (trigger first GC) | Platform-dependent (~21MB) |
-XX:MaxMetaspaceSize | Max size (unlimited = ไม่จำกัด) | Unlimited |
-XX:MinMetaspaceFreeRatio | Min % free after GC (expand ถ้าน้อยกว่า) | 40 |
-XX:MaxMetaspaceFreeRatio | Max % free after GC (shrink ถ้ามากกว่า) | 70 |
-XX:+UseCompressedClassPointers | Compress class pointers (ประหยัด memory) | Enabled (64-bit) |
-XX:CompressedClassSpaceSize | Size สำหรับ compressed class pointers | 1GB |
Monitoring Metaspace
# Command line jcmdVM.metaspace # JConsole / VisualVM / JMC - ดูใน Memory tab # Programmatic MemoryPoolMXBean metaspace = ManagementFactory.getMemoryPoolMXBeans().stream() .filter(mp -> mp.getName().contains("Metaspace")) .findFirst().orElse(null); if (metaspace != null) { MemoryUsage usage = metaspace.getUsage(); System.out.println("Used: " + usage.getUsed() / 1024 / 1024 + " MB"); System.out.println("Max: " + (usage.getMax() == -1 ? "Unlimited" : usage.getMax() / 1024 / 1024 + " MB")); }
Troubleshooting Metaspace OOM
- Class Loader Leak - ClassLoaders ไม่ถูก GC (common ใน Tomcat redeploy, OSGi)
- Dynamic Class Generation - CGLIB, ByteBuddy, JSP compilation, Groovy scripts
- Large number of classes - Microservices รวมกัน, Fat jars
แก้ไข
- ตั้ง
-XX:MaxMetaspaceSize=512m(ป้องกันกิน RAM หมด) - ใช้
-Xlog:gc+metaspace=debug(Java 9+) trace Metaspace GC - แก้ Class Loader Leak (ปิด ThreadLocal, DriverManager, Loggers ก่อน redeploy)
สรุป
PermGen = Fixed-size Heap area (Legacy, Java 7-)
Metaspace = Dynamic Native Memory (Modern, Java 8+)
Metaspace ลดปัญหา OOM และ tuning complexity แต่ต้องระวัง Native Memory exhaustion