JVM ตั้งค่าสถานะ CMSClassUnloadingEnabled ทำอะไรได้จริง


183

ฉันไม่สามารถหาคำจำกัดความของสิ่งที่ธงชาติ Java VM CMSClassUnloadingEnabledทำได้จริงนอกเหนือจากคำจำกัดความระดับสูงที่คลุมเครือเช่น "กำจัดปัญหา PermGen ของคุณ" ( ซึ่งไม่ใช่ btw)

ฉันดูเว็บไซต์ของ Sun / Oracle แล้วและแม้แต่รายการตัวเลือกก็ไม่ได้พูดว่าทำอะไร

จากการคาดคะเนชื่อของธงฉันเดาว่า CMS Garbage Collector ไม่ได้เป็นค่าเริ่มต้นในการยกเลิกการโหลดคลาสและค่าสถานะนี้จะเปิดใช้ แต่ฉันไม่แน่ใจ

คำตอบ:


219

อัปเดตคำตอบนี้เกี่ยวข้องกับ Java 5-7, Java 8 ได้แก้ไขสิ่งนี้แล้ว: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos ไปที่mt uulu

สำหรับ Java 5-7:

Oracle / Sun VM ที่เป็นมาตรฐานของโลกคือ: คลาสนั้นคงอยู่ตลอดไป ดังนั้นเมื่อโหลดเสร็จแล้วพวกเขายังคงอยู่ในความทรงจำแม้ว่าจะไม่มีใครสนใจอีกต่อไป โดยทั่วไปจะไม่มีปัญหาเนื่องจากคุณไม่มีคลาส "ตั้งค่า" ที่หมดจดจำนวนมาก (= ใช้หนึ่งครั้งเพื่อตั้งค่าและไม่ต้องทำอีกเลย) ดังนั้นแม้ว่าพวกเขาจะใช้เวลาถึง 1MB ใครจะสนใจ

แต่เมื่อเร็ว ๆ นี้เรามีภาษาอย่าง Groovy ซึ่งกำหนดคลาสที่รันไทม์ ทุกครั้งที่คุณเรียกใช้สคริปต์คลาสใหม่ (หรือมากกว่า) จะถูกสร้างขึ้นและจะอยู่ใน PermGen ตลอดไป หากคุณใช้เซิร์ฟเวอร์นั่นหมายความว่าคุณมีหน่วยความจำรั่ว

หากคุณเปิดใช้CMSClassUnloadingEnabledงาน GC จะกวาด PermGen ด้วยและลบคลาสที่ไม่ได้ใช้อีกต่อไป

[แก้ไข]คุณจะต้องเปิดใช้งานUseConcMarkSweepGCด้วย (ขอบคุณSam Hasler ) ดูคำตอบนี้: https://stackoverflow.com/a/3720052/2541


17
ตามstackoverflow.com/a/3720052/2541เพื่อCMSClassUnloadingEnabledให้มีผลกระทบใด ๆUseConcMarkSweepGCก็จะต้องตั้ง
Sam Hasler

1
ไม่แน่ใจว่าสิ่งนี้มีผลกระทบต่อความคิดในการใช้ UseConcatSweepGC อย่างไร แต่ดูเหมือนว่ามีข้อผิดพลาดที่แก้ไขล่าสุดใน CMSClassUnloadingEnabled มีการตั้งข้อสังเกตว่าแก้ไขได้ที่นี่: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Bill Rosmus

3
@ เควิน: ใช่แน่นอน ดูที่ด้านล่างของgroovy.codehaus.org/Running : "Groovy สร้างชั้นเรียนแบบไดนามิก แต่เริ่มต้น Java VM ไม่ประชาคมโลก PermGen หากคุณกำลังใช้ Java 6 หรือต่อมาเพิ่ม-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCเป็นสิ่งจำเป็นเพื่อเปิดใช้งานCMSClassUnloadingEnabled."
Aaron Digulla

1
บทความที่ดีเกี่ยวกับการใช้ UseConcMarkSweepGC และ CMSClassUnloadingEnabled ด้วยกัน blog.redfin.com/devblog/2012/06/…
วิกเตอร์

1
ไม่สามารถใช้งานได้อีกต่อไปสำหรับ 1.8: blogs.oracle.com/poonam/…
mt.uulu

35

ตามโพสต์บล็อกรายการที่สมบูรณ์ที่สุดของตัวเลือก -XX สำหรับ Java JVMจะกำหนดว่าเปิดใช้งานการยกเลิกการโหลดคลาสภายใต้ตัวรวบรวมขยะ CMS หรือไม่ falseเริ่มต้นคือ มีตัวเลือกอื่นที่เรียกClassUnloadingว่าเป็นtrueค่าเริ่มต้นซึ่ง (สันนิษฐาน) มีผลต่อการสะสมขยะอื่น ๆ

แนวคิดคือถ้า GC ตรวจพบว่าคลาสที่โหลดก่อนหน้านี้ไม่ได้ใช้ใน JVM อีกต่อไปมันสามารถเรียกคืนหน่วยความจำที่ใช้เพื่อเก็บคลาส bytecode และ / หรือเนทีฟโค้ดได้

การตั้งค่า CMSClassUnloadingEnabled อาจช่วยเหลือเกี่ยวกับปัญหา PermGen ของคุณถ้าคุณกำลังใช้เก็บ CMS แต่โอกาสที่คุณไม่ได้ใช้ CMS หรือมีหน่วยความจำรั่วที่เกี่ยวข้องกับ classloader ของแท้ ในกรณีหลังเรียนของคุณจะไม่ปรากฏให้ GC ไม่ได้ใช้ ... และจะไม่ถูกยกเลิกการโหลด


Aaron Digulla กล่าวว่า "คลาสนั้นเป็นแบบนี้ตลอดไป" สิ่งนี้ไม่เป็นความจริงอย่างเด็ดขาดแม้แต่ในโลกของจาวาล้วนๆ ในความเป็นจริงอายุการใช้งานของคลาสนั้นเชื่อมโยงกับ classloader ดังนั้นหากคุณสามารถจัดเรียงว่า classloader เป็นขยะที่รวบรวม (และไม่ได้เป็นเรื่องง่ายที่จะทำ) ชั้นเรียนที่โหลดก็จะเป็นขยะที่เก็บรวบรวม

ความจริงแล้วนี่คือสิ่งที่เกิดขึ้นเมื่อคุณทำการปรับใช้เว็บแอพใหม่ (หรืออย่างน้อยนั่นคือสิ่งที่จะเกิดขึ้นถ้าคุณสามารถหลีกเลี่ยงปัญหาที่ทำให้เกิดการรั่วไหลของที่เก็บ Permgen)


24

ตัวอย่างที่มีประโยชน์:

การตั้งค่า-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledบน Weblogic ของเรา 10.3 JVM ช่วยแก้ไขปัญหาที่การติดตั้ง JAX-WS สร้างคลาสพร็อกซีใหม่สำหรับทุกการเรียกใช้บริการเว็บในที่สุดนำไปสู่ข้อผิดพลาดของหน่วยความจำ

มันไม่สำคัญที่จะติดตาม รหัสต่อไปนี้จะส่งคืนคลาสพร็อกซีเดียวกันเสมอport

final MyPortType port = 
Service.create(
        getClass().getResource("/path/to.wsdl"), 
        new QName("http://www.example.com", "MyService"))
    .getPort(
        new QName("http://www.example.com", "MyPortType"), 
        MyPortType.class);

ภายในพร็อกซีนี้ได้มอบหมายให้กับอินสแตนซ์ของweblogic.wsee.jaxws.spi.ClientInstanceซึ่งได้มอบหมายให้$Proxy[nnnn]คลาสใหม่อีกครั้งซึ่งnเพิ่มขึ้นทุกครั้งที่โทร เมื่อเพิ่มแฟล็กnยังคงเพิ่มขึ้น แต่อย่างน้อยคลาสชั่วคราวเหล่านั้นจะถูกลบออกจากหน่วยความจำ

ในหมายเหตุทั่วไปนี้มีประโยชน์มากเมื่อใช้การสะท้อน Java และพร็อกซีอย่างหนัก java.lang.reflect.Proxy


+1 สำหรับการแบ่งปันประสบการณ์จริง นอกจากนี้เรายังพบปัญหานี้กับ torquebox ที่เซิร์ฟเวอร์สร้างคลาสจำนวนมากเนื่องจากกระบวนการรวบรวม JRuby
nurettin

7
โปรดทราบด้วยว่า-XX:+CMSPermGenSweepingEnabledเลิกใช้งานไปแล้ว-XX:+CMSClassUnloadingEnabled
nurettin

3
การแก้ไขที่แท้จริงสำหรับปัญหานี้คือการสร้างพอร์ตหนึ่งครั้งและนำกลับมาใช้ใหม่ นั่นคือวิธีที่ JAX-WS ควรจะใช้ พอร์ตยังปลอดภัย 100% เธรด
rustyx

@rustyx: คุณสามารถคืนการอ้างสิทธิ์ด้วยลิงก์ที่มีสิทธิ์ได้ไหม ฉันได้รับเสมอมากระวังอีกครั้งโดยใช้พร็อกซีบริการเว็บและไม่สมบูรณ์ ... เช่นดูข้อจำกัดความรับผิดชอบของ Apache CXF หรือคำถามนี้
Lukas Eder

1
@ rukavitsya: ตามที่ฉันพูดในคำตอบของฉัน ทุกครั้งที่ฉันเรียกตรรกะข้างต้นพร็อกซีใหม่จะถูกสร้างขึ้น
ลูคัสอีเดอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.