Xử lý lỗi java java.lang.OutOfMemoryError: Lỗi không gian PermGen


1222

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

java.lang.OutOfMemoryError: Không gian PermGen

Đây 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 một ứ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ố?


Tôi đã chiến đấu này 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 vì WebAppClassLoader của bạn không phải là rác được thu thập (nó có tham chiếu bên ngoài không bị xóa). việc 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 đến 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

13
sử dụng JDK 1.8: þ chào mừng bạn đến với MetaSpace
Rytek 20/03/2016

Nếu sử dụng Windows, hãy làm theo các hướng dẫn sau thay vì cố gắng đặt cờ theo cách thủ công trong 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 thời gian chạy. stackoverflow.com/questions/21104340/
Mạnh

Câu trả lời:


563

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 đó 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ài đặt, bạn nên chạy:

tomcat6w //ES//servicename

nơi servicename là tên của máy chủ như xem trong services.msc

Nguồn: bình luận của orx về Câu trả lời nhanh của Eric .


39
Bài viết dưới đây gợi ý -XX: + UseConcMarkSweepGC và -XX: MaxPermSize = 128m. my.opera.com/karmazilla/blog/2007/03/13/ từ
Taylor Leese

30
-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 nhiều thời gian hơn ba lần so với thông thường trên hệ thống của chúng tôi. Sử dụng cẩn thận.
Eldelshell

10
đã 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: + CMSClassUnloadingEnables -XX: + CMSPermGenSweepingEnables "- Khởi động lại tomcat bằng cách sử dụng: sudo /etc/init.d/tomcat6 bắt đầu
sami

24
Khi khởi động tomcat 6.0,29, từ logfile catalina.out của tôi: "Vui lòng sử dụng CMSClassUnloadingEnables thay cho CMSPermGenSweepingEnables trong tương lai"
knb

222
Trước hết, thật tuyệt vời khi giải thích những gì những lá cờ này thực sự làm. Chỉ cần nói: "làm điều đó và tận hưởng" là không đủ IMHO.
Nikem

251

Bạn nên thử -XX:MaxPermSize=128Mchứ không phải -XX:MaxPermGen=128M.

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


9
Trên thực tế, điều này sẽ chỉ 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.
Rade_303

Các tùy chọn này được giải thích tại đây: oracle.com/technetwork/java/javase/tech/iêng
amos

153

Lỗi máy chủ ứng dụng PermGen xảy ra sau nhiều lần triển khai rất có thể là do các tham chiếu được chứa bởi bộ 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 các tham chiếu được giữ 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ỉ giữa các lớp này bằng cách sử dụng các công cụ phân tích JVM (JDK6 +) hiện đại 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ơ sở dữ liệu, logger và các thư viện cấp khung cơ sở khác.

Xem rò rỉ Classloader: ngoại lệ "java.lang.OutOfMemoryError: PermGen space" đáng sợ và đặc biệt là bài đăng tiếp theo của nó .


3
Đâ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.
Rade_303

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

22
Trong khi về mặt lý thuyết có thể trả lời câu hỏi, tốt hơn là nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo.
Joachim Sauer

68

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 là như nhau, điều đó hoàn toàn không đúng. Bạn có thể còn rất nhiều dung lượng 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 tải vào JVM, tất cả dữ liệu meta của nó, cùng với Trình tải lớp, được lưu giữ trên khu vực PermGen và chúng sẽ được thu gom rác khi Trình nạp lớp đã tải chúng sẵn sàng để thu gom rác. Trong Case Classloader có rò rỉ bộ nhớ hơn tất cả các lớp được tải bởi nó sẽ vẫn còn trong bộ nhớ và gây ra lỗi hết mức permGen một 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 PermGen Space bằng cách sử dụng JVM param -XX:MaxPermSize-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.


3
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 trình nạp lớp? Bạn có đề nghị bất kỳ công cụ?
Amit

@amit cho các khuyến nghị công cụ, xem câu trả lời wiki cộng đồng 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 vào "OK"
Zeb

43

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


9
Vấn đề duy nhất là bạn chỉ trì hoãn việc không thể tránh khỏi - đến một lúc nào đó bạn cũng sẽ hết phò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 được nó vĩnh viễn.
Tim Howland

điều tương tự xảy ra trong Eclipse và bất cứ khi nào bạn có nhiều lớp tải động. các trình nạp lớp không bị loại bỏ và sống trong thế hệ vĩnh viễn vĩnh cửu
Matt

1
Tôi đã hết PermGen khi thực hiện một công việc đặc biệt lớn ở Hudson ... điều này đã khắc phục nó cho tôi.
HDave

10
@TimHowland, nó có thể là một sửa chữa vĩnh viễn nếu nguyên nhân gốc không phải là rò rỉ trình tải lớp, chỉ là quá nhiều lớp / dữ liệu tĩnh trong ứng dụng web của bạn.
Péter Török

gặp vấn đề tương tự như HDave khi xây dựng jenkins / hudson từ nguồn.
louisgab

38

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


56
và nếu nó vẫn tiếp tục thử XX:MaxPermSize=1024m:)
igo

38
và nếu nó vẫn tiếp tục, hãy thử XX: MaxPermSize = 2048m :)
Thomas

16
Và nếu nó vẫn còn, hãy suy nghĩ lại về ứng dụng của bạn !! Hoặc thử XX: MaxPermSize = 4096m :)
Jonathan Airey

17
bạn cũng có thể thử 8192m nhưng đó là một chút quá mức
Jacek Pietal

12
Overkill thực sự - 640KB nên là đủ cho bất cứ ai!
Joel Purra

28

Tôi đã thêm -XX: MaxPermSize = 128m (bạn có thể thử nghiệm hoạt động tốt nhất) cho VM Argument khi tôi đang sử dụng ide nhật thực. Trong hầu hết JVM, PermSize mặc định có dung lượng khoảng 64 MB , hết bộ nhớ nếu có quá nhiều lớp hoặc số lượng Chuỗi lớn 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 chuột vào máy chủ tomcat tại Tab Servers

nhập mô tả hình ảnh ở đây

BƯỚC 2 : Mở launch Conf và thêm -XX: MaxPermSize = 128mvào cuối các đối số VM hiện có .

nhập mô tả hình ảnh ở đây


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

23

Tôi đã cố gắng chống lại vấn đề này trong khi triển khai và không triển khai một ứng dụng web phức tạp, và nghĩ rằng tôi sẽ thêm một lời giải thích và giải pháp của mình.

Khi tôi triển khai một ứng dụng trên Apache Tomcat, 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à khi không triển khai, mọi thứ sẽ biến mất một cách độc đáo. Tuy nhiên, trong thực tế nó không hoàn toàn đơn giản.

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

Và sau một vài lần tái cấu trúc, chúng ta bắt 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ẽ phá hủy toàn bộ máy chủ, thay vì chỉ ứng dụng được triển khai lại, điều này thường không khả thi.

Vì vậy, thay vào đó tôi đã đưa ra 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 nếu 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à không ai nên sử dụng nó như 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 và dọn dẹp hợp lý . Lần duy nhất nên sử dụng là nếu có thư viện bên ngoài mà mã của bạn phụ thuộc vào (Trong trường hợp của tôi, đó là máy khách RADIUS) không cung cấp phương tiện để dọn sạch các tham chiếu tĩnh của chính nó.

Dù sao, với mã. Điều này nên được gọi tại thời điểm ứng dụng không triển khai - chẳng hạn như phương thức hủy của một 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();

Tôi biết đã hơn 8 năm kể từ khi tôi viết bài này, nhưng đâu đó giữa lúc đó và bây giờ tôi đã tìm thấy một nguyên nhân và giải pháp sâu xa hơn. Điều này là trong khi tất cả các lớp trong ứng dụng web được sở hữu bởi trình nạp lớp ngữ cảnh, thì luồng gọi lại cuộc gọi lại khởi động và tắt máy được sở hữu bởi trình nạp lớp cha. Điều này có nghĩa là nếu mã tắt máy khởi tạo một biến cục bộ luồng, điều này sẽ khiến trình nạp lớp cha kết thúc việc giữ một tham chiếu đến trình nạp lớp ngữ cảnh, ngăn chặn việc dọn dẹp tốt.
Edward Torbett

May mắn thay, có một cách khắc phục rất đơn giản - di chuyển tất cả mã hiện tại trong phương thức tắt máy sang phương thức chạy của đối tượng Thread mới. Sau đó, trong phương thức tắt máy, bắt đầu chuỗi này và chờ cho nó hoàn thành. Mã dọn dẹp sẽ được thực thi giống hệt nhau, nhưng bất kỳ biến cục bộ-luồng nào sẽ vẫn bị ràng buộc với trình nạp lớp ngữ cảnh thay vì rò rỉ.
Edward Torbett

20

Các java.lang.OutOfMemoryError: PermGenthông điệp không gian chỉ ra rằng khu vực Generation thường trực trong bộ nhớ được sử dụng hết.

Bất kỳ ứng dụng Java nào cũng được phép sử dụng một lượng bộ nhớ hạn chế. Dung lượng bộ nhớ chính xác mà ứng dụng cụ thể của bạn có thể sử dụng được chỉ định trong khi khởi động ứng dụng.

Bộ nhớ Java được phân tách thành các vùng khác nhau có thể được nhìn thấy trong hình ảnh sau đây:

nhập mô tả hình ảnh ở đây

Metaspace: Một không gian bộ nhớ mới được sinh ra

JVM JDK 8 HotSpot hiện đang sử dụng bộ nhớ riêng để biểu diễn siêu dữ liệu lớp và được gọi là Metaspace; tương tự như Oracle JRockit và IBM JVM.

Tin tốt là điều đó có nghĩa là không còn java.lang.OutOfMemoryError: PermGenvấn đề về không gian và bạn không cần phải điều chỉnh và giám sát không gian bộ nhớ này nữa bằng cách sử dụng Java_8_D Download hoặc cao hơn.


17

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. Điều này không thể được thực hiện với các đối số JVM thông thường (đặt kích thước heap ban đầu) và các đối số JVMXmx (đặt kích thước heap tối đa), vì như đã đề cập, không gian heap thế hệ vĩnh viễn tách biệt hoàn toàn với không gian Heap Java thông thường và các đối số này được đặt không gian cho không gian heap 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 jvms của Sun / OpenJDK) để làm cho kích thước của heap thế hệ vĩnh viễn lớn hơn:

 -XX:MaxPermSize=128m

Mặc định là 64m.

2) Cho phép quét

Một cách khác để giải quyết vấn đề đó là cho phép các lớp được dỡ tải để PermGen của bạn không bao giờ hết:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Những thứ như thế làm việc kỳ diệu cho tôi trong quá khứ. Mặc dù vậy, có một điều, có một sự đánh đổi hiệu suất đáng kể khi sử dụng chúng, vì các lần quét permgen sẽ thực hiện giống như thêm 2 yêu cầu cho mỗi yêu cầu bạn thực hiện hoặc một cái 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 bạn với sự đánh đổi.

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


Bài đăng tuyệt vời của @faisalbhagat faisalbhagat.blogspot.com/2014/09/ rèn
leomeker

Tùy chọn 2 là tuyệt vời, nhưng chỉ cần đượ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 để giữ nó cho môi trường phát triển mà thôi. Tuy nhiên PermGen đã bị xóa kể từ Java 8 openjdk.java.net/jeps/122
hdost


14

Tôi gặp vấn đề chúng ta đang nói ở đây, kịch bản của tôi là nhật thực + tomcat + jsf và những gì bạn đang làm là tạo ra một ứng dụng đơn giản cho tomcat. Tôi đã chỉ ra vấn đề tương tự ở đây, giải quyết nó như sau.

Trong nhật thực, vào tab máy chủ, nhấp đúp chuột vào máy chủ đã đăng ký trong trường hợp của tôi tomcat 7.0, nó sẽ mở máy chủ tệp của tôi Thông tin đăng ký chung. Trên phần "Thông tin chung", nhấp vào liên kết "Mở cấu hình khởi chạy" , điều này sẽ mở ra việc thực thi các tùy chọn máy chủ trong tab Đối số trong các đối số VM được thêm vào cuối hai mục nhập này

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

và sẵn sàng.


14

Câu trả lời đơn giản nhất hiện nay là sử dụng Java 8.

Nó không còn dự trữ bộ nhớ dành riêng cho không gian PermGen, cho phép bộ nhớ PermGen kết hợp với nhóm bộ nhớ thông thường.

Hãy nhớ rằng bạn sẽ phải xóa tất cả các -XXPermGen...=...tham số khởi động JVM không chuẩn nếu bạn không muốn Java 8 phàn nàn rằng chúng không làm gì cả.


Xin chào, câu trả lời này đã được đưa ra: stackoverflow.com/a/22897121/505893 . Hãy xóa câu trả lời của bạn, cho rõ ràng. Nếu cần bạn có thể cải thiện câu trả lời tôi đã đề cập. Cảm ơn;)
xanh lam

6
@bluish Cảm ơn bạn đã chỉ ra điều đó; tuy nhiên, câu trả lời đó đi ngang khi nói về OutOfMemoryExceptions và rò rỉ siêu dữ liệu. Nó cũng không đề cập đến những điểm rất quan trọng trong việc loại bỏ tùy chọn PermGen. Nói tóm lại, tôi không chắc mình sẽ cải thiện câu trả lời, mà là viết lại nó. Nếu đó chỉ là một cú chạm nhanh, tôi sẽ cảm thấy bớt do dự hơn, nhưng có vẻ như nó sẽ hơn nhiều so với một cú chạm nhanh, và tôi không muốn làm mất lòng tác giả ban đầu. Tuy nhiên, danh sách câu trả lời này là một bữa tối của một con chó lộn xộn, và có lẽ giết bài của tôi dù sao cũng sẽ tốt nhất.
Edwin Buck

8
  1. Mở tomcat7w từ thư mục bin của Tomcat hoặc gõ Monitor Tomcat trong menu start (một cửa sổ được mở với nhiều thông tin dịch vụ khác nhau).
  2. Trong vùng văn bản Tùy chọn Java nối thêm dòng này:

    -XX:MaxPermSize=128m
  3. Đặt nhóm bộ nhớ ban đầu thành 1024 (tùy chọn).
  4. Đặt nhóm bộ nhớ tối đa thành 1024 (tùy chọn).
  5. Nhấn Ok.
  6. Khởi động lại dịch vụ Tomcat.

6

Lỗi không gian Perm gen xảy ra do sử dụng không gian lớn thay vì sau đó jvm cung cấp không gian để thực thi mã.

Giải pháp tốt nhất cho vấn đề này trong các hệ điều hành UNIX là thay đổi một số cấu hình trên tệp bash. Các bước sau đây giải quyết vấn đề.

Chạy lệnh gedit .bashrctrên thiết bị đầu cuối.

Tạo JAVA_OTPSbiến có giá trị sau:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

Lưu tệp bash. Chạy lệnh exec bash trên thiết bị đầu cuối. Khởi động lại máy chủ.

Tôi hy vọng phương pháp này sẽ giải quyết vấn đề của bạn. Nếu bạn sử dụng phiên bản Java thấp hơn 8 thì vấn đề này đôi khi xảy ra. Nhưng nếu bạn sử dụng Java 8 thì vấn đề không bao giờ xảy ra.


5

Tăng kích thước thế hệ vĩnh viễn hoặc điều chỉnh các tham số GC sẽ KHÔNG giúp ích nếu bạn bị rò rỉ bộ nhớ thực. Nếu ứng dụng của bạn hoặc một số thư viện bên thứ 3 mà nó sử dụng, rò rỉ trình tải lớp, giải pháp thực sự và duy nhất là tìm ra rò rỉ này và khắc phục nó. Có một số công cụ có thể giúp bạn, một trong những công cụ gần đây là Plumbr , vừa phát hành phiên bản mới với các khả năng cần thiết.


5

Ngoài ra nếu bạn đang sử dụng log4j trong ứng dụng web của mình, hãy kiểm tra đoạn này trong tài liệu log4j .

Có vẻ như nếu bạn đang sử dụng PropertyConfigurator.configureAndWatch("log4j.properties"), bạn sẽ bị rò rỉ bộ nhớ khi bạn không triển khai ứng dụng web của mình.


4

Tôi có một sự kết hợp của Hibernate + Eclipse RCP, đã thử sử dụng -XX:MaxPermSize=512m-XX:PermSize=512mdường như nó đang hoạt động với tôi.


4

Đặt -XX:PermSize=64m -XX:MaxPermSize=128m. Sau này bạn cũng có thể thử tăng lên MaxPermSize. Hy vọng nó sẽ làm việc. Các công việc tương tự cho tôi. Cài đặt chỉ MaxPermSizekhông làm việc cho tôi.


4

Tôi đã thử một vài câu trả lời và điều duy nhất cuối cùng đã thực hiện công việc là cấu hình này cho plugin trình biên dịch trong pom:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <fork>true</fork>
        <meminitial>128m</meminitial>
        <maxmem>512m</maxmem>
        <source>1.6</source>
        <target>1.6</target>
        <!-- prevent PermGen space out of memory exception -->
        <!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
    </configuration>
</plugin>

hy vọng điều này sẽ giúp.


"ArgLine" không được maven-Trình biên dịch-plugin 2.4 nhận ra. nó chỉ hỗ trợ "Trình biên dịch", lỗi này: : javac <tùy chọn> <tệp nguồn>
Alex

Nếu giai đoạn biên dịch của bạn sắp hết permgen, hãy đặt <compArArgument> trên plugin maven-Trình biên dịch. Nếu các bài kiểm tra đơn vị sắp hết permgen, hãy đặt <argLine> trong maven-Surefire-plugin
qwerty

4

giải quyết điều này cho tôi là tốt; tuy nhiên, tôi nhận thấy rằng thời gian khởi động lại của servlet tồi tệ hơn nhiều, vì vậy trong khi nó tốt hơn trong sản xuất, thì đó là một lực cản trong phát triển.


3

Cấu hình của bộ nhớ phụ thuộc vào bản chất của ứng dụng của bạn.

Bạn đang làm gì đấy?

Số lượng giao dịch cần thiết là gì?

Bạn đang tải bao nhiêu dữ liệu?

Vân vân.

Vân vân.

Vân vân

Có lẽ bạn có thể cấu hình ứng dụng của mình và bắt đầu dọn dẹp một số mô-đun từ ứng dụng của bạn.

Rõ ràng điều này có thể xảy ra sau khi triển khai lại một ứng dụng một vài lần

Tomcat đã triển khai nóng nhưng nó tiêu thụ bộ nhớ. Hãy thử khởi động lại container của bạn một lần trong một thời gian. Ngoài ra, bạn sẽ cần biết lượng bộ nhớ cần thiết để chạy trong chế độ sản xuất, đây có vẻ là thời điểm tốt cho nghiên cứu đó.


3

Họ nói rằng phiên bản mới nhất của Tomcat (6.0.28 hoặc 6.0.29) xử lý nhiệm vụ triển khai lại các máy chủ tốt hơn nhiều .


3

Tôi gặp vấn đề chính xác như vậy, nhưng thật không may, không có giải pháp được đề xuất nào thực sự hiệu quả với tôi. Vấn đề đã không xảy ra trong quá trình triển khai và tôi cũng không thực hiện bất kỳ triển khai nóng nào.

Trong trường hợp của tôi, sự cố xảy ra mỗi lần tại cùng một thời điểm trong quá trình thực thi ứng dụng web của tôi, trong khi kết nối (thông qua chế độ ngủ đông) với cơ sở dữ liệu.

Liên kết này (cũng được đề cập trước đó) đã cung cấp đủ bên trong để giải quyết vấn đề. Di chuyển jdbc- (mysql) ra khỏi WEB-INF và vào thư mục jre / lib / ext / dường như đã giải quyết được vấn đề. Đây không phải là giải pháp lý tưởng, vì việc nâng cấp lên JRE mới hơn sẽ yêu cầu bạn cài đặt lại trình điều khiển. Một ứng cử viên khác có thể gây ra vấn đề tương tự là log4j, vì vậy bạn cũng có thể muốn di chuyển vấn đề đó


Nếu bạn không muốn bao gồm trình điều khiển trong jre / lib / ext, có lẽ bạn có thể nhận được kết quả tương tự bằng cách đưa trình điều khiển vào đường dẫn khởi động container của bạn. java -cp /path/to/jdbc-mysql-do.jar:/path/to/container/bootstrap.jar container.Start
Scot

3

Bước đầu tiên trong trường hợp này là kiểm tra xem GC có được phép dỡ các lớp khỏi PermGen hay không. JVM tiêu chuẩn khá bảo thủ trong vấn đề này - các lớp được sinh ra để sống mãi mãi. Vì vậy, một khi được tải, các lớp sẽ ở trong bộ nhớ ngay cả khi không còn mã nào sử dụng chúng nữa. Điều này có thể trở thành một vấn đề khi ứng dụng tạo ra nhiều lớp động và các lớp được tạo không cần thiết trong thời gian dài hơn. Trong trường hợp như vậy, cho phép JVM giải nén các định nghĩa lớp có thể hữu ích. Điều này có thể đạt được bằng cách thêm chỉ một tham số cấu hình vào tập lệnh khởi động của bạn:

-XX:+CMSClassUnloadingEnabled

Theo mặc định, điều này được đặt thành false và vì vậy để cho phép điều này, bạn cần đặt rõ ràng tùy chọn sau trong các tùy chọn Java. Nếu bạn bật CMSClassUnloadingEnables, GC cũng sẽ quét PermGen và xóa các lớp không còn được sử dụng. Hãy nhớ rằng tùy chọn này sẽ chỉ hoạt động khi UseConcMarkSweepGC cũng được bật bằng tùy chọn bên dưới. Vì vậy, khi chạy ParallelGC hoặc, God cấm, serial GC, hãy đảm bảo rằng bạn đã đặt GC của mình thành CMS bằng cách chỉ định:

-XX:+UseConcMarkSweepGC

3

Gán Tomcat thêm bộ nhớ KHÔNG phải là giải pháp thích hợp.

Giải pháp chính xác là dọn dẹp sau khi bối cảnh bị phá hủy và được tạo lại (triển khai nóng). Giải pháp là ngăn chặn rò rỉ bộ nhớ.

Nếu Máy chủ Tomcat / Webapp của bạn nói với bạn rằng không thể hủy đăng ký trình điều khiển (JDBC), thì hãy hủy đăng ký chúng. Điều này sẽ ngăn chặn rò rỉ bộ nhớ.

Bạn có thể tạo một ServletContextListener và định cấu hình nó trong tệp web.xml của bạn. Đây là một mẫu ServletContextListener:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;

import com.mysql.jdbc.AbandonedConnectionCleanupThread;

/**
 * 
 * @author alejandro.tkachuk / calculistik.com
 *
 */
public class AppContextListener implements ServletContextListener {

    private static final Logger logger = Logger.getLogger(AppContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        logger.info("AppContextListener started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        logger.info("AppContextListener destroyed");

        // manually unregister the JDBC drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("Unregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error unregistering driver %s", driver), e);
            }

        }

        // manually shutdown clean up threads
        try {
            AbandonedConnectionCleanupThread.shutdown();
            logger.info("Shutting down AbandonedConnectionCleanupThread");
        } catch (InterruptedException e) {
            logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
            e.printStackTrace();
        }        
    }
}

Và ở đây bạn định cấu hình nó trong tệp webDB của bạn:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>  

2

"Họ" sai vì tôi đang chạy 6.0,29 và có cùng một vấn đề ngay cả sau khi đặt tất cả các tùy chọn. Như Tim Howland đã nói ở trên, những lựa chọn này chỉ đưa ra những điều không thể tránh khỏi. Họ cho phép tôi triển khai lại 3 lần trước khi gặp lỗi thay vì mỗi lần tôi triển khai lại.


2

Trong trường hợp bạn nhận được điều này trong IDE nhật thực, ngay cả sau khi cài đặt các tham số --launcher.XXMaxPermSize, -XX:MaxPermSizev.v., nếu bạn gặp lỗi tương tự, rất có thể là nhật thực đang sử dụng một phiên bản lỗi của JRE đã được cài đặt bởi một số ứng dụng của bên thứ ba và được đặt thành mặc định. Các phiên bản lỗi này không nhận các tham số PermSize và do đó, bất kể bạn đặt gì, bạn vẫn tiếp tục nhận được các lỗi bộ nhớ này. Vì vậy, trong eclipse.ini của bạn thêm các tham số sau:

-vm <path to the right JRE directory>/<name of javaw executable>

Ngoài ra, hãy đảm bảo bạn đặt JRE mặc định trong các tùy chọn trong nhật thực thành phiên bản chính xác của java.


2

Cách duy nhất hiệu quả với tôi là với JVM của JRockit. Tôi có MyEclipse 8.6.

Heap của JVM lưu trữ tất cả các đối tượng được tạo bởi một chương trình Java đang chạy. Java sử dụng newtoán tử để tạo các đối tượng và bộ nhớ cho các đối tượng mới được phân bổ trên heap khi chạy. Thu gom rác là cơ chế tự động giải phóng bộ nhớ được chứa bởi các đối tượng không còn được chương trình tham chiếu.


2

Tôi đã có vấn đề tương tự. Của tôi là JDK 7 + Maven 3.0.2 + Struts 2.0 + dự án dựa trên tiêm chích phụ thuộc Google GUICE.

Bất cứ khi nào tôi thử chạy mvn clean packagelệnh, nó đã hiển thị lỗi sau và "XÂY DỰNG FAILURE" xảy ra

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; ngoại lệ lồng nhau là java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Nguyên nhân bởi: java.lang.OutOfMemoryError: PermGen space

Tôi đã thử tất cả các mẹo và thủ thuật hữu ích ở trên nhưng tiếc là không có cách nào hiệu quả với tôi. Những gì làm việc cho tôi được mô tả từng bước dưới đây: =>

  1. Chuyển đến tệp pom.xml của bạn
  2. Tìm kiếm <artifactId>maven-surefire-plugin</artifactId>
  3. Thêm một <configuration>phần tử mới và sau đó <argLine>phần tử con trong đó vượt qua -Xmx512m -XX:MaxPermSize=256mnhư được hiển thị bên dưới =>

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

Hy vọng nó sẽ giúp, lập trình hạnh phúc :)

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.