2013-10-24 21 views
5

Tôi đang cố gắng tạo các lớp và tải chúng vào thời gian chạy.
Tôi đang sử dụng đối tượng ClassLoader để tải các lớp. Vì tôi không muốn hết bộ nhớ PermGen, đôi khi tôi không tham khảo bộ nạp lớp và tạo bộ nạp mới để tải các lớp mới sẽ được sử dụng. Điều này có vẻ hoạt động tốt và tôi không nhận được PermGen hết bộ nhớ. Vấn đề là khi tôi làm điều đó, sau một thời gian tôi nhận được lỗi sau:Tránh Permagen hết bộ nhớ và giới hạn vượt quá GC vượt quá

java.lang.OutOfMemoryError: GC overhead limit exceeded 

Vì vậy, câu hỏi của tôi là, khi tôi nên bỏ tham khảo các bộ nạp lớp để tránh cả hai lỗi ?:
Tôi có nên theo dõi trong mã của tôi, việc sử dụng PermGen để tôi không tham chiếu đến trình nạp lớp học và gọi số System.gc() khi sử dụng PermGen gần với giới hạn?
Hoặc tôi có nên làm theo một cách tiếp cận khác không?
Cảm ơn

Trả lời

6

Không có câu trả lời đúng cho điều này.

Một mặt, nếu hủy liên kết trình nạp lớp đang giải quyết các vấn đề rò rỉ permgen của bạn, thì bạn nên tiếp tục thực hiện điều đó.

Mặt khác, lỗi "vượt quá giới hạn vượt quá GC" có nghĩa là ứng dụng của bạn đang dành quá nhiều thời gian thu gom rác thải. Trong hầu hết các trường hợp, điều này có nghĩa là heap của bạn quá đầy. Nhưng điều đó có thể có nghĩa là một trong hai điều sau:

  • Heap quá nhỏ cho các yêu cầu của ứng dụng.

  • Ứng dụng của bạn bị rò rỉ bộ nhớ.

Bạn có thể giả định rằng sự cố là vấn đề cũ và chỉ tăng kích thước heap. Nhưng nếu vấn đề thực sự là sau đó, sau đó tăng kích thước heap chỉ là trì hoãn không thể tránh khỏi ... và chính xác điều cần làm sẽ là tìm thấysửa lỗi rò rỉ bộ nhớ.


Không gọi System.gc(). Nó sẽ không giúp được gì.

+0

Tôi đang sử dụng jvisualvm để giám sát việc sử dụng đống, kích thước tối đa là 1 Gb và mức sử dụng thay đổi từ 200 mb đến 600 mb, vì vậy nó nằm ngoài giới hạn. – otonakav

+0

@otonakav - có thể có một số vấn đề với thông số điều chỉnh GC của bạn. –

1

Bạn đang tải cùng một lớp nhiều lần? Vì bạn nên cache lớp đã tải.

Nếu không, bạn đang tải bao nhiêu lớp? Nếu chúng có nhiều, bạn có thể phải sửa một giới hạn các lớp được tải (số này có thể dựa trên kích thước heap hoặc số dựa trên lượng bộ nhớ cần có để có một lớp đã tải) và loại bỏ ít nhất được sử dụng khi tải tiếp theo.

+0

Có lẽ giới hạn sẽ làm để giảm thiểu số lần tôi bỏ tham chiếu trình nạp lớp để GC không chạy quá nhiều lần, nhưng tôi cho rằng GC sẽ không chạy nếu có nhiều đống và chỉ PermGen vì tôi không tham chiếu đến trình nạp lớp, đặc biệt nếu nó vượt qua giới hạn trên không. – otonakav

+0

Tôi đã cố gắng chỉ ra rằng vấn đề có thể là trong việc sử dụng bộ nạp lớp và không phải là trình nạp lớp. –

1

Tôi có tình huống tương tự với việc xếp lớp. Tôi đang sử dụng một số trình nạp lớp để mô phỏng nhiều JVM bên trong kiểm tra JUnit (thường được sử dụng để làm việc với cụm Oracle Coherence), nhưng tôi cũng đã sử dụng thành công kỹ thuật này để bắt đầu cụm nhiều nút HBase/Hadoop bên trong JVM).

Vì nhiều lý do khác nhau, các thử nghiệm có thể yêu cầu khởi động lại JVM "ảo", có nghĩa là mất quyền tải lớp cũ và tạo mới.

Đôi khi JVM trì hoãn sự kiện dỡ lớp nếu bạn dùng Full GC, dẫn đến nhiều sự cố sau này.

Một kỹ thuật tôi thấy hữu ích khi buộc JVM thu thập PermSpace đang theo dõi.

public static void forcePermSpaceGC(double factor) { 
    if (PERM_SPACE_MBEAN == null) { 
     // probably not a HotSpot JVM 
     return; 
    } 
    else { 
     double f = ((double)getPermSpaceUsage())/getPermSpaceLimit(); 
     if (f > factor) { 

      List<String> bloat = new ArrayList<String>(); 
      int spree = 0; 
      int n = 0; 
      while(spree < 5) { 
       try { 
        byte[] b = new byte[1 << 20]; 
        Arrays.fill(b, (byte)('A' + ++n)); 
        bloat.add(new String(b).intern()); 
        spree = 0; 
       } 
       catch(OutOfMemoryError e) { 
        ++spree; 
        System.gc(); 
       } 
      } 
      return; 
     } 
    } 
} 

Full sourcecode

Tôi điền PermSpace với String sử dụng intern() cho đến khi JVM sẽ thu thập chúng.

Nhưng

  • Tôi đang sử dụng kỹ thuật mà để thử nghiệm
  • kết hợp khác nhau của phần cứng phiên bản/JVM có thể yêu cầu ngưỡng khác nhau, vì vậy nó thường nhanh hơn để khởi động lại toàn bộ JVM thay vì buộc nó để thu thập đúng là tất cả rác
Các vấn đề liên quan