Câu hỏi Xử lý lỗi “java.lang.OutOfMemoryError: PermGen space”


Gần đây tôi đã gặp lỗi này trong ứng dụng web của tôi:

java.lang.OutOfMemoryError: Khoảng trống PermGen

Nó là một ứng dụng Hibernate / JPA + IceFaces / JSF điển hình chạy trên Tomcat 6 và JDK 1.6. Rõ ràng điều này có thể xảy ra sau khi triển khai lại ứng dụng một vài lần.

Điều gì gây ra nó và những gì có thể được thực hiện để tránh nó? Làm cách nào để khắc phục sự cố?


1180
2017-09-18 03:29


gốc


Tôi đã chiến đấu trong nhiều giờ, nhưng tôi không có tin tốt. Xem câu hỏi liên quan của tôi: stackoverflow.com/questions/1996088/… Bạn vẫn có thể bị rò rỉ bộ nhớ, ví dụ: các lớp không phải là rác được thu thập bởi vì WebAppClassLoader của bạn không phải là rác được thu thập (nó có một tham chiếu bên ngoài không bị xóa). tăng PermGen sẽ chỉ trì hoãn OutOfMemoryError, và cho phép thu gom rác lớp là điều kiện tiên quyết, nhưng sẽ không thu gom rác các lớp nếu trình nạp lớp của chúng vẫn có tham chiếu tới nó. - Eran Medan
Tôi gặp lỗi này khi thêm taglib hiển thị. Loại bỏ như vậy cũng đã giải quyết được lỗi. Tại sao như vậy? - masT
Và làm thế nào bạn chạy vào nó? - Thorbjørn Ravn Andersen
sử dụng JDK 1.8: þ chào mừng bạn đến với MetaSpace - Rytek
Nếu sử dụng Windows, hãy làm theo các hướng dẫn này thay vì cố gắng đặt cờ theo cách thủ công trong các tệp cấu hình. Điều này đặt đúng các giá trị trong sổ đăng ký được gọi bởi Tomcat trong suốt thời gian chạy. stackoverflow.com/questions/21104340/… - MacGyver


Các câu trả lời:


Giải pháp là thêm các cờ này vào dòng lệnh JVM khi Tomcat được khởi động:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Bạn có thể làm điều đó bằng cách tắt dịch vụ tomcat, sau đó đi vào thư mục Tomcat / bin và chạy tomcat6w.exe. Trong tab "Java", thêm các đối số vào hộp "Tùy chọn Java". Nhấp vào "OK" và sau đó khởi động lại dịch vụ.

Nếu bạn gặp lỗi dịch vụ được chỉ định không tồn tại dưới dạng dịch vụ được cài đặt Bạn nên chạy đi:

tomcat6w //ES//servicename

Ở đâu Tên dịch vụ là tên của máy chủ được xem trong services.msc

Nguồn: nhận xét của orx về Eric's Agile Các Câu Trả Lời.


550
2017-09-17 22:23



Bài viết dưới đây gợi ý -XX: + UseConcMarkSweepGC và -XX: MaxPermSize = 128m. my.opera.com/karmazilla/blog/2007/03/13/… - Taylor Leese
-XX: + CMSPermGenSweepingEnabled Tùy chọn này làm giảm hiệu suất. Nó làm cho mỗi yêu cầu mất ba lần nhiều thời gian hơn bình thường trên các hệ thống của chúng tôi. Sử dụng cẩn thận. - Eldelshell
làm việc cho tôi - cảm ơn - Tôi đang làm điều này trên Ubuntu 10.10 với Tomcat6 - Tôi đã tạo một tệp mới: /usr/share/tomcat6/bin/setenv.sh và thêm dòng sau vào đó: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Khởi động lại tomcat sử dụng: sudo /etc/init.d/tomcat6 bắt đầu - sami
Ngày khởi động tomcat 6.0.29, từ tệp catalina.out logfile của tôi: "Vui lòng sử dụng CMSClassUnloadingEnabled thay cho CMSPermGenSweepingEnabled trong tương lai" - knb
Trước hết nó sẽ là tuyệt vời để giải thích những gì những lá cờ thực sự làm. Chỉ cần nói: "làm điều đó và tận hưởng" là không đủ IMHO. - Nikem


Bạn thử tốt hơn -XX:MaxPermSize=128M thay vì -XX:MaxPermGen=128M.

Tôi không thể nói chính xác việc sử dụng bộ nhớ này, nhưng nó phải làm với số lượng các lớp được nạp vào JVM. (Do đó cho phép nạp lớp cho tomcat có thể giải quyết vấn đề.) Nếu các ứng dụng của bạn tạo và biên dịch các lớp khi chạy nó có nhiều khả năng cần một vùng bộ nhớ lớn hơn giá trị mặc định.


247
2017-09-18 02:09



Trên thực tế, điều này sẽ chỉ trì hoãn OOMError. Xem câu trả lời dưới đây bắt đầu bởi anon với hai liên kết đến blog frankkieviet. - RockyMM
Các tùy chọn này được giải thích ở đây: oracle.com/technetwork/java/javase/tech/… - amos


Máy chủ ứng dụng PermGen lỗi xảy ra sau khi nhiều lần triển khai có nhiều khả năng gây ra bởi các tham chiếu được tổ chức bởi vùng chứa vào trình nạp lớp của ứng dụng cũ của bạn. Ví dụ: sử dụng lớp cấp nhật ký tùy chỉnh sẽ khiến tham chiếu được tổ chức bởi trình nạp lớp của máy chủ ứng dụng. Bạn có thể phát hiện các rò rỉ liên lớp này bằng cách sử dụng các công cụ phân tích JVM hiện đại (JDK6 +) như jmap và jhat để xem các lớp nào tiếp tục được giữ trong ứng dụng của bạn và thiết kế lại hoặc loại bỏ việc sử dụng chúng. Các nghi phạm thông thường là các cơ sở dữ liệu, logger và các thư viện cấp cơ sở khác.

Xem Sự rò rỉ của trình nạp lớp: không gian "java.lang.OutOfMemoryError: PermGen space" đáng sợvà đặc biệt là bài đăng tiếp theo.


152
2018-03-11 22:24



Đây chỉ là giải pháp thực sự cho vấn đề, có thể trong một số trường hợp quá khó thực hiện. - RockyMM
Một nguồn rất tốt khác là people.apache.org/~markt/presentations/… (từ người quản lý phát hành Tomcat !!). - gavenkoa
Trong khi điều này về mặt lý thuyết có thể trả lời câu hỏi, nó sẽ là thích hợp hơn để bao gồm các phần thiết yếu của câu trả lời tại đây và cung cấp liên kết để tham khảo. - Joachim Sauer


Những sai lầm phổ biến mà mọi người mắc phải là nghĩ rằng không gian heap và không gian permgen giống nhau, điều đó không hoàn toàn đúng. Bạn có thể có nhiều không gian còn lại trong heap nhưng vẫn có thể hết bộ nhớ trong permgen.

Nguyên nhân phổ biến của OutofMemory trong PermGen là ClassLoader. Bất cứ khi nào một lớp được nạp vào JVM, tất cả các dữ liệu meta của nó, cùng với Classloader, được lưu giữ trên vùng PermGen và chúng sẽ được thu thập rác khi Trình nạp lớp đã tải chúng sẵn sàng để thu thập rác. Trong trường hợp Classloader có một rò rỉ bộ nhớ hơn tất cả các lớp được nạp bởi nó sẽ vẫn còn trong bộ nhớ và gây ra permGen outofmemory khi bạn lặp lại nó một vài lần. Ví dụ cổ điển là Java.lang.OutOfMemoryError: PermGen Space trong Tomcat.

Bây giờ có hai cách để giải quyết vấn đề này:
1. Tìm nguyên nhân của Rò rỉ bộ nhớ hoặc nếu có bất kỳ rò rỉ bộ nhớ nào.
2. Tăng kích thước của không gian PermGen bằng cách sử dụng param JVM -XX:MaxPermSize và -XX:PermSize.

Bạn cũng có thể kiểm tra 2 Giải pháp của Java.lang.OutOfMemoryError trong Java để biết thêm chi tiết.


65



Làm thế nào để vượt qua param -XX:MaxPermSize and -XX:PermSize?? Tôi không thể tìm thấy catalina.bat. Phiên bản tomcat của tôi là 5.5.26. - Deckard
Làm thế nào để tìm rò rỉ bộ nhớ của bộ nạp lớp? Bạn có đề xuất bất kỳ công cụ nào không? - Amit
@amit cho các đề xuất công cụ, xem câu trả lời của cộng đồng wiki về câu hỏi này. - Barett
@Deckard đi vào thư mục Tomcat / bin và chạy tomcat6w.exe. Trong tab "Java", thêm các đối số vào hộp "Tùy chọn Java". Nhấp "OK" - Zeb


Sử dụng tham số dòng lệnh -XX:MaxPermSize=128m cho một JVM Sun (rõ ràng là thay thế 128 cho bất kỳ kích thước nào bạn cần).


39



Vấn đề duy nhất là bạn chỉ trì hoãn việc không thể tránh khỏi - tại một số điểm bạn sẽ chạy ra khỏi khoảng không ở đó. Đó là một giải pháp thực dụng tuyệt vời, nhưng nó không giải quyết nó vĩnh viễn. - Tim Howland
cùng một điều xảy ra trong Eclipse và bất cứ lúc nào bạn có rất nhiều lớp tải động. các trình nạp lớp không được xử lý và sống trong thế hệ vĩnh cửu cho tất cả vĩnh cửu - Matt
Tôi đã chạy ra khỏi PermGen khi thực hiện một công việc đặc biệt lớn Hudson ... điều này cố định nó cho tôi. - HDave
@TimHowland, nó có thể là một sửa chữa vĩnh viễn nếu nguyên nhân gốc rễ không phải là rò rỉ bộ nạp lớp, chỉ có quá nhiều lớp / dữ liệu tĩnh trong ứng dụng web của bạn. - Péter Török
có cùng một vấn đề như HDave khi xây dựng jenkins / hudson từ nguồn. - louisgab


Thử -XX:MaxPermSize=256m và nếu nó vẫn còn, hãy thử -XX:MaxPermSize=512m


35



và nếu nó vẫn tiếp tục cố gắng XX:MaxPermSize=1024m :) - igo
và nếu nó vẫn tồn tại, hãy thử XX: MaxPermSize = 2048m :) - Thomas
Và nếu nó vẫn còn tồn tại, hãy suy nghĩ lại ứng dụng của bạn !! Hoặc thử XX: MaxPermSize = 4096m :) - jon.airey
bạn cũng có thể thử 8192m nhưng đó là một chút quá mức cần thiết - Prozi
Overkill thực sự - 640KB nên là đủ cho bất cứ ai! - Joel Purra


tôi thêm  -XX: MaxPermSize = 128m (bạn có thể thử nghiệm hoạt động tốt nhất) để Đối số VM khi tôi đang sử dụng id eclipse. Trong hầu hết các JVM, PermSize mặc định khoảng 64 MB hết bộ nhớ nếu có quá nhiều lớp hoặc số lượng lớn các chuỗi trong dự án.

Đối với nhật thực, nó cũng được mô tả tại câu trả lời.

BƯỚC 1 : Nhấp đúp vào máy chủ tomcat tại Máy chủ Chuyển hướng

enter image description here

BƯỚC 2 : Mở ra mắt Conf và thêm -XX: MaxPermSize = 128m đến cuối của hiện tại VM tranh luận.

enter image description here


24



Cảm ơn bạn đã có câu trả lời chi tiết nhất (Lưu ý: nhấp vào "Mở cấu hình khởi chạy" để mở cửa sổ "chỉnh sửa cấu hình" ... nhưng tôi đã sử dụng các thông số sau: "-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled" - Chris Sim


Tôi đã được butting đầu của tôi chống lại vấn đề này trong khi triển khai và undeploying một ứng dụng web phức tạp quá, và nghĩ rằng tôi muốn thêm một lời giải thích và giải pháp của tôi.

Khi tôi triển khai một ứng dụng trên Apache Tomcat, một ClassLoader mới được tạo cho ứng dụng đó. ClassLoader sau đó được sử dụng để tải tất cả các lớp của ứng dụng, và trên undeploy, tất cả mọi thứ của nghĩa vụ phải đi xa độc đáo. Tuy nhiên, trong thực tế nó không phải là khá đơn giản.

Một hoặc nhiều lớp được tạo trong suốt thời gian của ứng dụng web giữ một tham chiếu tĩnh, ở đâu đó dọc theo dòng, tham chiếu đến ClassLoader. Vì tham chiếu ban đầu là tĩnh, không có lượng rác thu thập sẽ làm sạch tham chiếu này lên - ClassLoader, và tất cả các lớp được nạp, đang ở đây để ở.

Và sau một vài redeploys, chúng ta gặp OutOfMemoryError.

Bây giờ điều này đã trở thành một vấn đề khá nghiêm trọng. Tôi có thể chắc chắn rằng Tomcat được khởi động lại sau mỗi lần triển khai lại, nhưng điều đó sẽ gỡ toàn bộ máy chủ, thay vì chỉ ứng dụng đang được triển khai lại, thường không khả thi.

Vì vậy, thay vào đó tôi đã đặt cùng một giải pháp trong mã, hoạt động trên Apache Tomcat 6.0. Tôi chưa thử nghiệm trên bất kỳ máy chủ ứng dụng nào khác và phải nhấn mạnh rằng điều này rất có thể không hoạt động mà không sửa đổi trên bất kỳ máy chủ ứng dụng nào khác.

Tôi cũng muốn nói rằng cá nhân tôi ghét mã này, và rằng không ai nên sử dụng điều này như là một "sửa chữa nhanh" nếu mã hiện tại có thể được thay đổi để sử dụng các phương pháp tắt máy và dọn dẹp thích hợp. Thời gian duy nhất này nên được sử dụng là nếu có một thư viện bên ngoài mã của bạn phụ thuộc vào (Trong trường hợp của tôi, nó là một máy khách RADIUS) không cung cấp một phương tiện để dọn sạch các tham chiếu tĩnh của riêng nó.

Dù sao, với mã. Điều này nên được gọi tại thời điểm mà ứng dụng đang không triển khai - chẳng hạn như phương thức hủy của servlet hoặc (cách tiếp cận tốt hơn) một phương thức contextDestroyed của ServletContextListener.

//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
    try {
        classLoaderClassesField = clazz.getDeclaredField("classes");
    } catch (Exception exception) {
        //do nothing
    }
    clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);

List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));

for (Object o : classes) {
    Class c = (Class)o;
    //Make sure you identify only the packages that are holding references to the classloader.
    //Allowing this code to clear all static references will result in all sorts
    //of horrible things (like java segfaulting).
    if (c.getName().startsWith("com.whatever")) {
        //Kill any static references within all these classes.
        for (Field f : c.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers())
                    && !Modifier.isFinal(f.getModifiers())
                    && !f.getType().isPrimitive()) {
                try {
                    f.setAccessible(true);
                    f.set(null, null);
                } catch (Exception exception) {
                    //Log the exception
                }
            }
        }
    }
}

classes.clear();

22





Ngoài ra, bạn có thể chuyển sang JRockit xử lý permgen khác nhau sau đó là jvm của mặt trời. Nó thường có hiệu suất tốt hơn là tốt.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html


15



Trong khi JRockit thực sự không có PermGen, nhưng điều này sẽ không giúp đỡ về lâu dài. Bạn sẽ nhận được java.lang.OutOfMemoryError: There is insufficient native memory thay thế. - stracktracer


1) Tăng kích thước bộ nhớ PermGen

Điều đầu tiên người ta có thể làm là để làm cho kích thước của không gian heap thế hệ vĩnh viễn lớn hơn. Không thể thực hiện điều này bằng các tham số JVM thông thường (đặt kích thước ban đầu) và –Xmx (thiết lập kích thước heap tối đa), như đã đề cập, không gian heap thế hệ vĩnh viễn hoàn toàn tách biệt với không gian Java Heap thông thường, và các đối số này đặt không gian cho vùng lưu trữ Java thông thường này. Tuy nhiên, có những đối số tương tự có thể được sử dụng (ít nhất là với Sun / OpenJDK jvms) để làm cho kích thước của đống thế hệ vĩnh viễn lớn hơn:

 -XX:MaxPermSize=128m

Mặc định là 64m.

2) Bật quét

Một cách khác để chăm sóc điều đó là tốt để cho phép các lớp được dỡ xuống để PermGen của bạn không bao giờ cạn kiệt:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Những thứ như thế đã làm phép thuật cho tôi trong quá khứ. Một điều mặc dù, có một hiệu suất đáng kể trong việc sử dụng chúng, vì permlink sweeps sẽ tạo ra 2 yêu cầu bổ sung cho mỗi yêu cầu bạn thực hiện hoặc một thứ gì đó dọc theo các dòng đó. Bạn sẽ cần phải cân bằng việc sử dụng của mình với sự cân bằng.

Bạn có thể tìm thấy các chi tiết của lỗi này.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html


14



Bài đăng tuyệt vời của @faisalbhagat faisalbhagat.blogspot.com/2014/09/… - meurer
Tùy chọn 2 là rất tốt, nhưng chỉ được cảnh báo rằng nó không nên được sử dụng trong môi trường sản xuất. Thông thường tốt nhất là chỉ giữ cho môi trường phát triển. Tuy nhiên, PermGen bị loại bỏ khỏi Java 8 openjdk.java.net/jeps/122 - hdost