2013-06-14 30 views
16

Tiếp cận của tôi là tạo ra trăm ngàn bộ sưu tập địa phương và cư chúng với chuỗi ngẫu nhiên, một cái gì đó như thế này:Làm thế nào để tái tạo Java OutOfMemoryError - giới hạn overhead GC vượt

SecureRandom random = new SecureRandom(); 
    for(int i = 0 ; i < 100000 ; i++){ 
     HashMap<String, String> map = new HashMap<String, String>(); 
     for(int j = 0 ; j < 30 ; j++){ 
      map.put(new BigInteger(130, random).toString(32), new BigInteger(130, random).toString(32)); 
     } 
    } 

tôi đã cung cấp -XX: + UseGCOverheadLimit tham số JVM quá, nhưng không thể nhận được lỗi. Có cách nào dễ dàng và đáng tin cậy/hack để có được lỗi này?

+0

Lưu bản đồ vào bộ sưu tập khác được khai báo bên ngoài vòng lặp 'for' và thêm' while (true) 'trước vòng lặp' for' đầu tiên. –

+1

Câu hỏi hay! Thật dễ dàng để tái tạo một "OOM heap", nhưng việc tái tạo giới hạn trên cao là MUCH phức tạp hơn ... Tôi tự hỏi liệu nó có khả thi không!(có mục đích, nghĩa là) – fge

+0

Làm cho bên ngoài cho vòng lặp như trong khi (đúng) điều này là tái tạo lỗi. – VKPRO

Trả lời

9

Vì bạn chưa chấp nhận bất kỳ câu trả lời nào, tôi cho rằng không ai trong số họ đã làm việc cho bạn. Đây là một trong đó sẽ. Nhưng trước tiên, xem xét lại các the conditions that trigger this error:

The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered

Vì vậy, bạn phải tiêu thụ hầu hết các heap, giữ cho nó được phân bổ, và sau đó phân bổ rất nhiều rác. Đặt rất nhiều thứ vào một Map sẽ không làm điều này cho bạn.

public static void main(String[] argv) 
throws Exception 
{ 
    List<Object> fixedData = consumeAvailableMemory(); 
    while (true) 
    { 
     Object data = new byte[64 * 1024 - 1]; 
    } 
} 


private static List<Object> consumeAvailableMemory() 
throws Exception 
{ 
    LinkedList<Object> holder = new LinkedList<Object>(); 
    while (true) 
    { 
     try 
     { 
      holder.add(new byte[128 * 1024]); 
     } 
     catch (OutOfMemoryError ex) 
     { 
      holder.removeLast(); 
      return holder; 
     } 
    } 
} 

Phương thức consumeAvailableMemory() lấp đầy đống với bộ nhớ tương đối nhỏ. "Tương đối nhỏ" là quan trọng bởi vì JVM sẽ đặt các đối tượng "lớn" (512k byte trong kinh nghiệm của tôi) trực tiếp vào thế hệ được thuê, để lại thế hệ trẻ trống rỗng.

Sau khi tôi đã tiêu thụ phần lớn vùng heap, tôi chỉ phân bổ và loại bỏ. Kích thước khối nhỏ hơn trong giai đoạn này là quan trọng: Tôi biết rằng tôi sẽ có đủ bộ nhớ cho ít nhất một phân bổ, nhưng có lẽ không quá hai. Điều này sẽ giữ cho GC hoạt động.

Chạy này tạo ra các lỗi mong muốn trong dưới một giây:

> java -Xms1024m -Xmx1024m GCOverheadTrigger 
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded 
    at GCOverheadTrigger.main(GCOverheadTrigger.java:12) 

Và, cho đầy đủ, đây là JVM mà tôi đang sử dụng:

> java -version 
java version "1.6.0_45" 
Java(TM) SE Runtime Environment (build 1.6.0_45-b06) 
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode) 

Và bây giờ câu hỏi của tôi dành cho bạn: tại sao bạn muốn làm điều này?

+0

+1 để có cách tiêu thụ vĩnh viễn * gần như * tất cả bộ nhớ, để tái sản xuất. –

+0

Trả lời câu hỏi của bạn: muốn kiểm tra xem JVM có thể phục hồi bằng cách nào đó từ trạng thái này hay không, có thể với sự trợ giúp của người giám sát hoặc dịch vụ khác. Thành thật mà nói tôi cũng không nhận được điểm ngoại lệ này kể từ khi JVM trở nên không phản hồi ngay sau khi ngoại lệ này. Tôi thà mong đợi JVM chấm dứt (cách tiếp cận thất bại nhanh). – mkorszun

+1

@mkorszun - đó thực sự là điểm ngoại lệ: tắt JVM thay vì tiếp tục cố gắng giải phóng dung lượng. Giống như hầu hết các lỗi OOM, nó chỉ ra rằng bạn đã không phân bổ đủ heap để chạy chương trình của bạn (đôi khi "đủ" là vô hạn, nhưng thường xuyên hơn chương trình có một ràng buộc thực sự trên mà nó cần). Một lần mà tôi thấy lỗi này trong một chương trình thực sự, chúng tôi đã duy trì một tập hợp lớn các đối tượng sẽ được cập nhật bởi các thư đến. Các tin nhắn được ngắn ngủi, vì vậy sẽ được thu thập liên tục. Lỗi đã biến mất khi chúng tôi tăng heap. – kdgregory

2

này:

HashMap<String, String> map = new HashMap<String, String>(); 

được scoped trong vòng lặp và không có bên ngoài (dài hạn) tham chiếu đến bản đồ được tạo ra như lặp loop. Do đó mỗi bản đồ sẽ đủ điều kiện thu gom rác thải vào cuối mỗi lần lặp vòng lặp.

Bạn cần tạo bộ sưu tập các đối tượng bên ngoài vòng lặp và sử dụng vòng lặp để điền tập hợp đó.

+0

Mặc dù điều đó chắc chắn sẽ kích hoạt một "OOM heap", không phải là một giới hạn trên không, phải không? – fge

0

Tôi nghĩ rằng điều này sẽ làm các trick ... nếu bạn chạy nó đủ lâu:

HashMap<Long, String> map = new HashMap<Long, String>(); 
for (long i = 0; true; i++) { 
    for (int j = 0; j < 100; j++) { 
     String s = "" + j; 
     map.put(i, s); 
    } 
} 

Những gì tôi đang làm đang dần xây dựng số tiền phi rác, trong khi tạo ra một số lượng đáng kể của rác cùng một lúc. Nếu điều này được chạy cho đến khi phần rác không được lấp đầy gần hết tất cả đống, GC sẽ đến một điểm mà% thời gian thu thập rác vượt quá ngưỡng.

+0

nó vẫn ném java.lang.OutOfMemoryError: Vùng heap Java – mkorszun

+0

Tăng bộ đếm vòng lặp cho vòng lặp bên trong. –

+0

Tôi đoán bạn luôn có thể '-Xmx8M' nếu bạn muốn rút ngắn thời gian chạy;) – fge

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