เคยไหม...ที่ทุกครั้ง เวลาที่เราเขียน Code บน NetBean หรือ Eclipse แล้วค้างๆๆๆๆๆ หรือ Deploy แล้วค้างแล้ว Dump ขึ้นตัวแดงมาเลยย... แล้วก็อ้างว่าเครื่องเก่าบ้าง กากบ้าง ต้องไปเพิ่ม Ram ให้เยอะขึ้น
จากการที่ท๊อปได้เข้าไปอ่านตาม Blog ต่างๆ เขาสรุปสาเหตุไว้ ดังนี้...
1. ปัญหาจากช่วง Deploy และ Undeploy
-ช่วง runtime แต่ละ application จะถูกโหลดผ่านทาง application classloader โดยทำหน้าที่ โหลดไฟล์ .class จาก jar files และเมื่อ undeploy application นั้น classloader มันจะทำการละทิ้ง class ที่ได้มีการโหลดเข้ามา แล้วจะถูกจัดการโดย garbage collector ต่อมาในภายหลังเพื่อคืนทรัพยากรสู่ระบบ
และจากเหตุการณ์ตรงนี้แหละ....
-บางครั้ง classloader อาจยังมีการเก็บบางสิ่งที่ถูกโหลดเข้ามาไว้อยู่ และปกป้องมันจาก garbage collector เนื่องจากว่ามันอาจจะถูกใช้งานอยู่ ทำให้ garbage collector ไม่สามารถเข้ามาจัดการได้ จึงเป็นเหตุทำให้เกิดข้อผิดพลาด java.lang.OutOfMemoryError: PermGen space ได้
2. ปัญหาจากการจัดการ Memory ใน VM
-เดิมที memory ที่มีอยู่ใน Virtual Machine (VM) จะถูกหารไปใช้งานโดย number of region ซึ่งหนึ่งในนั้น คือ region ที่เป็น PermGen space (permanent generation space) ซึ่งเป็นพื้นที่ของ memory สำหรับโหลด class file เข้ามา
-สำหรับ size of memory region นั้น จะมีการกำหนดไว้อย่างคงที่โดยไม่มีการเปลี่ยนแปลงเมื่อ VM ทำงานอยู่ เราสามารถกำหนด size of region โดย -XX:MaxPermSize เช่น -XX:MaxPermSize = 256m หมายความว่า เรากำหนด size of memory region สูงสุดที่ 256 MB โดยหากเราไม่มีการกำหนด โดยพื้นฐานแล้วทางจะมีการกำหนดไว้ที่ 64 MB
-เดิมที memory ที่มีอยู่ใน Virtual Machine (VM) จะถูกหารไปใช้งานโดย number of region ซึ่งหนึ่งในนั้น คือ region ที่เป็น PermGen space (permanent generation space) ซึ่งเป็นพื้นที่ของ memory สำหรับโหลด class file เข้ามา
-สำหรับ size of memory region นั้น จะมีการกำหนดไว้อย่างคงที่โดยไม่มีการเปลี่ยนแปลงเมื่อ VM ทำงานอยู่ เราสามารถกำหนด size of region โดย -XX:MaxPermSize เช่น -XX:MaxPermSize = 256m หมายความว่า เรากำหนด size of memory region สูงสุดที่ 256 MB โดยหากเราไม่มีการกำหนด โดยพื้นฐานแล้วทางจะมีการกำหนดไว้ที่ 64 MB
3. ปัญหาจาก garbage collector
-เนื่องจาก garbage collector ไม่สามารถคืนทรัพยากรสู่ระบบได้
วิธีการที่ garbage collector จัดการ... คือ ต้องเก็บ classes ใหม่ที่กำลังโหลดเข้ามาใน memory เป็นเหตุทำให้ VM นั้นเกิดการขาดแคลน space ใน memory region จึงต้องมี JAVA heap ไว้เพื่อช่วยจัดสรร memory ให้เพียงพอต่อ size of Object ที่อาศัยอยู่บน process heap
ปัญหาที่เกิดตามมา ก็คือ... เกิด Object นั้นออกจาก process และคืน memory สู่ระบบ
-เนื่องจากว่า JAVA application จะทำงานตาม process เดี่ยวๆ ของแต่ละ process ที่ทำงานอยู่ โดยจะไม่มีการแชร์ memory ร่วมกันระหว่าง process ซึ่งแต่ละ process จะถูกจัดสรร memory ให้แต่ละ process เองโดย JVM ที่เรียกว่า process heap
เพราะฉะนั้น... การตั้งค่าพารามิเตอร์ –Xmx นั้นไม่ได้ช่วยอะไรมาก โดยพารามิเตอร์ดังกล่าว เป็นเพียงการกำหนด size of total heap เท่านั้น และไม่ได้ส่งผลกระทบอะไรต่อ size of PermGen region เลย
-เนื่องจาก garbage collector ไม่สามารถคืนทรัพยากรสู่ระบบได้
วิธีการที่ garbage collector จัดการ... คือ ต้องเก็บ classes ใหม่ที่กำลังโหลดเข้ามาใน memory เป็นเหตุทำให้ VM นั้นเกิดการขาดแคลน space ใน memory region จึงต้องมี JAVA heap ไว้เพื่อช่วยจัดสรร memory ให้เพียงพอต่อ size of Object ที่อาศัยอยู่บน process heap
ปัญหาที่เกิดตามมา ก็คือ... เกิด Object นั้นออกจาก process และคืน memory สู่ระบบ
-เนื่องจากว่า JAVA application จะทำงานตาม process เดี่ยวๆ ของแต่ละ process ที่ทำงานอยู่ โดยจะไม่มีการแชร์ memory ร่วมกันระหว่าง process ซึ่งแต่ละ process จะถูกจัดสรร memory ให้แต่ละ process เองโดย JVM ที่เรียกว่า process heap
เพราะฉะนั้น... การตั้งค่าพารามิเตอร์ –Xmx นั้นไม่ได้ช่วยอะไรมาก โดยพารามิเตอร์ดังกล่าว เป็นเพียงการกำหนด size of total heap เท่านั้น และไม่ได้ส่งผลกระทบอะไรต่อ size of PermGen region เลย
หลักๆ คือ ...
-PermSize ไม่เพียงพอต่อการโหลด class file มาเก็บไว้ใน memory PermGen space
สิ่งที่ต้องทำ คือ ...
-กำหนดค่า PermGen space และ heap size ให้เพียงพอต่อความต้องการใช้งาน
โดยทั่วไปเราจะกำหนด Environment Variables จาก JAVA_OPTS ซึ่งเป็น variable name ไว้กำหนดค่าต่างๆ ดังนี้
-PermSize ไม่เพียงพอต่อการโหลด class file มาเก็บไว้ใน memory PermGen space
โดยทั่วไปเราจะกำหนด Environment Variables จาก JAVA_OPTS ซึ่งเป็น variable name ไว้กำหนดค่าต่างๆ ดังนี้
JAVA_OPTS="–Xms256m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=512m "
–Xms (initial java total heap size) ในกรณีที่เกิดปัญหาทำงานช้า
-Xmx : maximum java total heap size
-XX:PermSize : initial permanent generation space
-XX:MaxPermSize : maximum permanent generation space
นอกจากนี้ ยังมีพารามิเตอร์ตัวอื่นที่น่าสนใจ เช่น
-Xss128m เป็นการกำหนด stack size เท่ากับ 128MB
-ในแต่ละ thread ใน VM นั้น จะมี stack อยู่ โดย stack size จะจำกัดจำนวนของ thread ไว้ตามที่เราจะสามารถมีได้
ดังนั้น ถ้าจำนวนของ thread > stack size จะทำให้ขาดแคลน memory ตามที่แต่ละ thread มันต้องการ
ดังนั้น ถ้าจำนวนของ thread > stack size จะทำให้ขาดแคลน memory ตามที่แต่ละ thread มันต้องการ
-Xmn100m เป็นการกำหนด size of the heap สำหรับ young generation เท่ากับ 100MB
-memory ที่ถูกใช้งานโดย JVM จะถูกจัดเป็น generation
-ขั้นที่ 1 : generation จะแบ่งตามช่วงเวลาที่ memory pool นั้นได้ถือครอง object ในช่วงเวลาแตกต่างกันออกไป โดย object ใหม่ที่ถูกเรียกเข้ามาใช้งานนั้นจะมีการจอง memory เพื่อใช้งานใน young generation region (บางครั้งอาจจะเรียกว่า new generation region) เมื่อไม่ได้ใช้งานจะถูกนำไปเก็บไว้ที่ memory old generation region
-ขั้นที่ 2 : หาก memory young generation region เต็มแล้ว garbage collector จะทำการเรียกคืนหน่วยจำส่วนหนึ่ง ที่ไม่ได้มีการใช้งานแล้ว จาก old generation region แบ่งไปให้กับ young generation region
เดิมทีนั้น จะมีการแบ่ง generation ของ total heap size ต่อมาได้มีการแบ่ง old generation ออกมาเป็น tenured generation หลังจากที่ generational memory system นั้นได้ทำการหาร heap เข้าไป ใน sized partitions ที่ถูกแบ่งไว้อย่างระมัดระวังจะถูกเรียกว่า generation
-ขั้นที่ 1 : generation จะแบ่งตามช่วงเวลาที่ memory pool นั้นได้ถือครอง object ในช่วงเวลาแตกต่างกันออกไป โดย object ใหม่ที่ถูกเรียกเข้ามาใช้งานนั้นจะมีการจอง memory เพื่อใช้งานใน young generation region (บางครั้งอาจจะเรียกว่า new generation region) เมื่อไม่ได้ใช้งานจะถูกนำไปเก็บไว้ที่ memory old generation region
-ขั้นที่ 2 : หาก memory young generation region เต็มแล้ว garbage collector จะทำการเรียกคืนหน่วยจำส่วนหนึ่ง ที่ไม่ได้มีการใช้งานแล้ว จาก old generation region แบ่งไปให้กับ young generation region
เดิมทีนั้น จะมีการแบ่ง generation ของ total heap size ต่อมาได้มีการแบ่ง old generation ออกมาเป็น tenured generation หลังจากที่ generational memory system นั้นได้ทำการหาร heap เข้าไป ใน sized partitions ที่ถูกแบ่งไว้อย่างระมัดระวังจะถูกเรียกว่า generation
–Xmn จะกำหนด size of the heap ที่ถูกจัดสรรสำหรับ Eden generation of the heap เพราะเริ่มแรก object ที่มีการใช้งานจะจอง memory เบื้องต้นบน Eden ก่อนที่จะถูกนำไปเก็บบน memory ทั้ง 2 spaces ระหว่าง survivor spaces จนกระทั่งมันไม่ได้ถูกเรียกใช้งาน และถูกนำไปเก็บไว้ยัง old generation region
older generation = (ขนาดของ -Xmx) – (ขนาดของ -Xmn)
-ดังนั้น... –Xmn จะต้องมีค่าต่ำกว่า –Xmx เสมอ
โดยทั่วไปเราไม่ต้องการ Eden ที่ใหญ่เกินไป หรือใช้มากกว่าที่ garbage collector จะเรียกคืนสู่ระบบได้ จึงไม่จำเป็นต้องตั้งค่าให้กับพารามิเตอร์ -Xmn เพิ่มก็ได้
โดยทั่วไปเราไม่ต้องการ Eden ที่ใหญ่เกินไป หรือใช้มากกว่าที่ garbage collector จะเรียกคืนสู่ระบบได้ จึงไม่จำเป็นต้องตั้งค่าให้กับพารามิเตอร์ -Xmn เพิ่มก็ได้
-นอกจากนี้ ก็มีการแนะนำต่ออีกว่า... ควรเลือก JDK ให้เหมาะสมกับ OS เพราะ OS 64 bit จะมี heap size default มากกว่า OS 32 bit เพื่อรองรับ size of object ที่ใหญ่ขึ้น
Keywork : JAVA Performance Tuning, Java Concurrency in Practice
Refference :
-เรื่อง Dealing with “java.lang.OutOfMemoryError: PermGen space” error
http://stackoverflow.com/questions/88235/dealing-with-java-lang-outofmemoryerror-permgen-space-errorhttp://www.mkyong.com/tomcat/tomcat-javalangoutofmemoryerror-permgen-space/
-เรื่อง java.lang.OutOfMemoryError: Permgen space
https://plumbr.eu/outofmemoryerror/permgen-space
ไม่มีความคิดเห็น:
แสดงความคิดเห็น