2011-11-05 30 views
9

Tôi làm việc trên ứng dụng Tomcat sử dụng bộ thu CMS cùng với thanh bộ nhớ để kích hoạt GC. Khi tôi tải lại các ứng dụng web, đôi khi tôi kết thúc trong một tình huống mà gen cũ đủ đầy đủ để kích hoạt GC nhưng các Trình nạp lớp chết không được thu thập.Khi nào thì gen perm được thu thập?

Tôi đọc rằng các lớp học được phân bổ vào thể loại perm và đoán rằng chúng được bỏ qua bởi bộ sưu tập gen cũ. Tôi đã viết bài kiểm tra sau đây để kiểm tra lý thuyết này.

package test; 

import java.io.IOException; 
import java.io.InputStream; 

import org.apache.commons.io.IOUtils; 

/* 
JVM Options: 
-server -XX:+UseMembar -XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly -Xms100m -Xmx100m 
-XX:PermSize=100m -XX:NewSize=10m -XX:MaxNewSize=10m 
-verbose:gc -Xloggc:gc.log -XX:+PrintGCTimeStamps 
-XX:+PrintGCDetails 
*/ 
public class ClassLoaderTest extends ClassLoader 
{ 
    @Override 
    protected synchronized Class<?> loadClass(String xiName, boolean xiResolve) 
     throws ClassNotFoundException 
    { 
    if (xiName.equals("test")) 
    { 
     // When asked to load "test", load Example.class 
     Class<?> c = Example.class; 
     String className = c.getName(); 
     String classAsPath = className.replace('.', '/') + ".class"; 
     InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); 
     byte[] classData = null; 
     try 
     { 
     classData = IOUtils.toByteArray(stream); 
     } 
     catch (IOException e) 
     { 
     e.printStackTrace(); 
     } 
     return defineClass(className, classData, 0, classData.length); 
    } 
    return super.loadClass(xiName, xiResolve); 
    } 

    public static class Example {} 
    public static ClassLoaderTest classLoaderTest; 

    public static void main(String[] args) throws Exception 
    { 
    // Allocate CL in new gen 
    classLoaderTest = new ClassLoaderTest(); 

    // Load a class - allocated in perm gen 
    classLoaderTest.loadClass("test"); 

    // Discard CL 
    classLoaderTest = null; 

    // Pause at end 
    Thread.sleep(99 * 60 * 1000); 
    } 

    public final byte[] mMem = new byte[85 * 1024 * 1024]; 
} 

Tôi chạy lớp này và theo dõi kết quả sử dụng VisualVM và thấy rằng có thực sự nhiều Old and Young gen bộ sưu tập xảy ra mà không có sự Classloader chết được thu thập và do đó mảng byte lớn vẫn trong bộ nhớ.

VisualVM Visual GC

Điều gì sẽ kích hoạt Perm Gen được thu thập?

+0

Bạn biết chữ "Perm" là viết tắt của [... right?] (Http://en.wiktionary.org/wiki/permanent#Adjective) –

+4

Bộ nhớ được cấp phát trong Java Perm Gen vẫn có thể được thu thập. JVM sử dụng Perm Gen để giữ dữ liệu mà nó dự kiến ​​sẽ được giải phóng rất hiếm khi. – mchr

Trả lời

4

Kiểm tra các tùy chọn JVM "CMSPermGenSweepingEnabled" và "CMSClassUnloadingEnabled". (Có rất nhiều cuộc thảo luận trên mạng tái sử dụng của họ.) Đặc biệt, người đầu tiên giả sử bao gồm PermGen trong một bộ sưu tập rác chạy. Theo mặc định, không gian PermGen không bao giờ được bao gồm trong bộ sưu tập rác (và do đó phát triển không có giới hạn).

+1

Nó không phát triển mà không có giới hạn, có một ràng buộc trên rất chắc chắn. Đó là lý do tại sao bạn thường gặp phải sự rò rỉ bộ nạp lớp học đáng sợ: https://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java –

+0

@Cameron Skinner + Điểm được chụp! Nó _attempts_ phát triển không liên quan đến MaxPermSize :-) – mazaneicha

+1

Tôi đã thử thêm -XX: + CMSPermGenSweepingEnabled -XX: + CMSClassUnloadingEnabled vào JVM của tôi. Tôi thấy rằng chỉ -XX: + CMSClassUnloadingEnabled thực sự đã làm bất cứ điều gì. Tôi cũng ngạc nhiên khi thấy rằng gen perm chỉ được thu thập sau 2 phút ngay sau khi bộ sưu tập gen trẻ thứ hai. – mchr

Các vấn đề liên quan