Cờ JVM CMSClassUnloadingEnables thực sự làm gì?


183

Cả đời tôi không thể tìm thấy định nghĩa về cờ Java VM CMSClassUnloadingEnabledthực sự làm gì, ngoài một số định nghĩa cấp cao rất mờ như "thoát khỏi các vấn đề PermGen của bạn" ( mà nó không , btw).

Tôi đã xem trên trang web của Sun / Oracle và ngay cả danh sách tùy chọn cũng không thực sự nói nó làm gì.

Dựa vào tên của cờ, tôi đoán rằng Trình thu gom rác CMS không mặc định bỏ các lớp và cờ này bật nó lên - nhưng tôi không chắc chắn.

Câu trả lời:


219

Cập nhật Câu trả lời này có liên quan đến Java 5-7, Java 8 đã sửa lỗi này: https://bloss.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos đi đến mt. uulu

Đối với Java 5-7:

Giao diện chuẩn của Oracle / Sun VM trên thế giới là: Các lớp học là mãi mãi. Vì vậy, một khi được tải, họ sẽ ở trong bộ nhớ ngay cả khi không ai quan tâm nữa. Điều này thường không có vấn đề gì vì bạn không có nhiều lớp "thiết lập" hoàn toàn (= được sử dụng một lần để thiết lập và sau đó không bao giờ lặp lại). Vì vậy, ngay cả khi họ chiếm 1MB, ai quan tâm.

Nhưng gần đây, chúng ta có các ngôn ngữ như Groovy, định nghĩa các lớp khi chạy. Mỗi khi bạn chạy một tập lệnh, một (hoặc nhiều) lớp mới sẽ được tạo và chúng sẽ ở lại PermGen mãi mãi. Nếu bạn đang chạy một máy chủ, điều đó có nghĩa là bạn bị rò rỉ bộ nhớ.

Nếu bạn bật CMSClassUnloadingEnabled, GC cũng sẽ quét PermGen và xóa các lớp không còn được sử dụng.

[EDIT] Bạn cũng sẽ phải bật UseConcMarkSweepGC(nhờ Sam Hasler ). Xem câu trả lời này: https://stackoverflow.com/a/3720052/2541


17
Theo stackoverflow.com/a/3720052/2541 cho CMSClassUnloadingEnabledcó bất kỳ tác động, UseConcMarkSweepGCcũng phải được thiết lập
Sam Hasler

1
Không chắc điều này ảnh hưởng đến ý tưởng sử dụng UseConcatSweepGC như thế nào, nhưng có vẻ như đã xảy ra lỗi gần đây trong CMSClassUnloadingEnabled. Nó được nhận xét là đã sửa ở đây: bug.sun.com/ormsdatabase/view_orms.do?orms_id=8000325
Bill Rosmus

3
@Kevin: Vâng, chắc chắn. Xem ở dưới cùng của groovy.codehaus.org/Running : "Groovy tạo ra các lớp học năng động, nhưng mặc định Java VM không GC các PermGen Nếu bạn đang sử dụng Java 6 hoặc mới hơn, thêm -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCLà cần thiết để cho phép CMSClassUnloadingEnabled."
Aaron Digulla

1
Một bài viết hay về việc sử dụng UseConcMarkSweepGC và CMSClassUnloadingEnables cùng nhau. blog.redfin.com/devblog/2012/06/ khăn
Victor

1
không còn giá trị 1.8: blogs.oracle.com/poonam/...
mt.uulu

35

Theo bài đăng trên blog Danh sách đầy đủ nhất các tùy chọn -XX cho Java JVM , nó xác định xem việc hủy tải lớp có được bật trong trình thu gom rác CMS hay không. Mặc định là false. Có một tùy chọn khác được gọi ClassUnloadingtruetheo mặc định (có lẽ) ảnh hưởng đến các công cụ thu gom rác khác.

Ý tưởng là nếu GC phát hiện ra rằng một lớp được tải trước đó không còn được sử dụng ở bất cứ đâu trong JVM, thì nó có thể lấy lại bộ nhớ được sử dụng để giữ các lớp mã byte và / hoặc mã gốc.

Đặt CMSClassUnloadingEnables có thể giúp giải quyết vấn đề permgen của bạn nếu bạn hiện đang sử dụng trình thu thập CMS . Nhưng khả năng là bạn không sử dụng CMS hoặc bạn bị rò rỉ bộ nhớ liên quan đến trình nạp lớp chính hãng. Trong trường hợp sau, lớp của bạn sẽ không bao giờ xuất hiện với GC không được sử dụng ... và do đó sẽ không bao giờ được tải.


Aaron Digulla nói rằng "các lớp học là mãi mãi". Điều này không hoàn toàn đúng, ngay cả trong thế giới thuần Java. Trong thực tế, thời gian tồn tại của một lớp được gắn với trình nạp lớp của nó. Vì vậy, nếu bạn có thể sắp xếp rằng trình nạp lớp là rác được thu thập (và đó không phải lúc nào cũng dễ thực hiện) thì các lớp mà nó đã tải cũng sẽ là rác được thu thập.

Trong thực tế, đây là những gì xảy ra khi bạn thực hiện triển khai lại một ứng dụng web. (Hoặc ít nhất, đó là điều sẽ xảy ra, nếu bạn có thể tránh được các vấn đề dẫn đến rò rỉ lưu trữ permgen.)


24

Một ví dụ trong đó hữu ích:

Cài đặt -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledtrên Weblogic 10.3 JVM của chúng tôi đã giúp giải quyết vấn đề trong đó việc triển khai JAX-WS đã tạo ra một lớp proxy mới cho mỗi cuộc gọi dịch vụ web, cuối cùng dẫn đến lỗi bộ nhớ.

Nó không tầm thường để theo dõi. Đoạn mã sau luôn trả về cùng một lớp proxy choport

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);

Trong nội bộ, proxy này được ủy quyền cho một thể hiện weblogic.wsee.jaxws.spi.ClientInstance, một lần nữa được ủy quyền cho một $Proxy[nnnn]lớp mới , nơi nđược tăng lên trong mỗi cuộc gọi. Khi thêm các cờ, nvẫn được tăng lên, nhưng ít nhất những lớp tạm thời đó đã bị xóa khỏi bộ nhớ.

Nói một cách tổng quát hơn, điều này có thể rất hữu ích khi sử dụng nhiều sự phản chiếu và proxy của Java thông qua java.lang.reflect.Proxy


+1 để chia sẻ kinh nghiệm thực tế. Chúng tôi cũng gặp vấn đề này trên torquebox nơi máy chủ tạo ra một số lượng lớn các lớp do các quá trình biên dịch của JRuby.
Nurettin 22/03/13

7
cũng lưu ý rằng -XX:+CMSPermGenSweepingEnabledkhông được ủng hộ-XX:+CMSClassUnloadingEnabled
Nurettin 22/03/13

3
Một sửa chữa thực sự cho vấn đề này mặc dù là tạo cổng một lần và sử dụng lại nó. Đó là cách JAX-WS được sử dụng. Các cổng cũng là chủ đề an toàn 100%.
rustyx

@rustyx: Bạn có thể quay lại yêu cầu đó với một số liên kết có thẩm quyền không? Tôi luôn rất thận trọng khi tái sử dụng proxy dịch vụ web và khai ... Ví dụ thấy kỹ khuyến cáo Apache CXF . Hoặc câu hỏi này
Lukas Eder

1
@rukavitsya: Như tôi đã nói trong câu trả lời của mình. Mỗi lần tôi gọi logic trên, một proxy mới đã được tạo
Lukas Eder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.