2012-01-29 17 views
5

Tôi đã đọc Unveiling the java.lang.Out OfMemoryError và tôi đã tự hỏi nếu tôi đã hiểu nó một cách chính xác. Có đúng là nếu máy ảo Java ném mộtTôi có gặp phải java.lang.OutOfMemoryError ngay cả khi thiếu bộ nhớ không?

java.lang.OutOfMemoryError: yêu cầu kích thước mảng vượt quá giới hạn VM

Nó có nghĩa là VM đã từ chối việc tạo ra một mảng vì nó đã vượt quá một được xác định trước giới hạn (vượt quá mức ưu tiên của VM) và không phải vì tôi đã hết bộ nhớ trong vùng lưu trữ này?

Tôi có quyền nói rằng java.lang.OutOfMemoryError: Requested array size exceeds VM limit không cho biết thiếu bộ nhớ?

Thậm chí nếu tôi có không giới hạn nhớ ở khắp mọi nơi, máy ảo Java vẫn có thể ném một java.lang.OutOfMemoryError: Requested array size exceeds VM limit nếu nó không giống như yêu cầu của tôi để tạo ra một loạt các n kích thước?

+0

Xem http://stackoverflow.com/questions/1880687/how-to-simulate-the-out-of-memory-requested-array-size-exceeds-vm-limit – skaffman

Trả lời

9

Trích dẫn tin nhắn Troubleshooting Guide for Java SE 6 with HotSpot VM

3.1.3 Chi tiết: Requested array size exceeds VM limit (inline đậm là của tôi):

Chi tiết nhắn Requested array size exceeds VM limit chỉ ra rằng ứng dụng (hoặc các API được sử dụng bởi ứng dụng đó) cố gắng phân bổ một mảng lớn hơn kích thước heap. Ví dụ: nếu ứng dụng cố gắng phân bổ một mảng 512MB nhưng kích thước heap tối đa là 256MB thì OutOfMemoryError sẽ bị ném với lý do Requested array size exceeds VM limit. Trong hầu hết các trường hợp, sự cố là vấn đề cấu hình (kích thước heap quá nhỏ) hoặc lỗi dẫn đến ứng dụng cố tạo một mảng lớn, ví dụ: khi số lượng phần tử trong mảng được tính bằng một thuật toán tính toán kích thước không chính xác.


UPDATE: khuyến khích bởi các @Pacerier tôi đã làm một số thử nghiệm nhanh chóng.Tôi đã viết một chương trình mẫu:

public class VmLimitTest { 

    public static final int SIZE = 2; 

    public static void main(String[] args) throws InterruptedException { 
     while(true) { 
      byte[] a = new byte[SIZE * 1024 * 1024]; 
      TimeUnit.MILLISECONDS.sleep(10); 
     } 
    } 
} 

Và chạy nó với các tùy chọn JVM sau:

-Xms192m -Xmx192m -XX:NewRatio=2 -XX:SurvivorRatio=6 -XX:+PrintGCDetails 

Đây là ý nghĩa của chúng:

  • Cả đống là 192 MiB (-Xms192m -Xmx192m)
  • Không gian thế hệ trẻ (eden + survivor) là 64 MiB, thế hệ cũ là 128 MiB (-XX:NewRatio=2)
  • Mỗi không gian sống sót (trong số hai) là 8 MiB, vì vậy 48 MiB còn lại cho eden (1: 6 tỷ lệ, -XX:SurvivorRatio=6)

Trong khi kiểm tra tôi phát hiện ra những điều sau đây:

  • Nếu mảng mới được tạo có thể vừa với eden (dưới 48 MiB), chương trình chạy tốt
  • Đáng ngạc nhiên, khi kích thước mảng vượt quá kích thước eden, nhưng có thể vừa với eden và không gian sống sót (từ 48 đến 56 MiB), JVM có thể phân bổ một đối tượng duy nhất trên cả eden và survivor (chồng chéo tw o khu vực). Khéo léo!
  • Khi kích thước mảng vượt quá eden + đơn sống sót (trên 56 MiB) đối tượng mới được tạo sẽ được đặt trực tiếp trong thế hệ cũ, bỏ qua không gian eden và người sống sót. Điều này cũng có nghĩa là đột ngột GC đầy đủ được thực hiện tất cả các thời gian - rất xấu!
  • tôi có thể dễ dàng phân bổ 127 MiB dữ liệu nhưng cố gắng để phân bổ 129 MiB sẽ ném OutOfMemoryError: Java heap space

Đây là điểm mấu chốt - bạn không thể tạo một đối tượng với kích thước lớn hơn so với thế hệ cũ. Cố gắng làm như vậy sẽ dẫn đến lỗi OutOfMemoryError: Java heap space. Vì vậy, khi chúng ta có thể mong đợi đáng sợ Requested array size exceeds VM limit?

Tôi đã thử chạy cùng một chương trình với nhiều đối tượng lớn hơn. Nhấn vào giới hạn độ dài mảng tôi chuyển sang long[] và có thể dễ dàng lên tới 7 GiB. Với 128 MiB của heap tối đa khai báo JVM vẫn đang ném OutOfMemoryError: Java heap space (!) Tôi đã quản lý để kích hoạt lỗi OutOfMemoryError: Requested array size exceeds VM limit cố gắng phân bổ 8 GiB trong một đối tượng duy nhất. Tôi đã thử nghiệm điều này trên một máy tính Linux 32 bit với 3 GiB bộ nhớ vật lý và 1 GiB trao đổi.

Điều đó đang được nói rằng có thể bạn không bao giờ nên nhấn lỗi này. Các tài liệu có vẻ không chính xác/lỗi thời, nhưng nó là đúng trong một kết luận: điều này có lẽ là một lỗi vì việc tạo các mảng lớn như vậy là rất không phổ biến.

+2

http: //java.sys- con.com/node/1229281 nói rằng VM có thể từ chối việc tạo một mảng và ném kích thước mảng 'OOM: Requested vượt quá giới hạn VM 'ngay cả khi có đủ bộ nhớ trong heap để tạo mảng đó. Bạn có nghĩa là để nói rằng đó là sai (vì VM ** không được ** làm như vậy nếu có đủ bộ nhớ trong heap)? – Pacerier

+0

@Pacerier: +1, tôi nghĩ tài liệu hơi quá ngắn gọn ở đây. Heap được chia thành trẻ, người sống sót và thế hệ cũ. Tôi đoán ngoại lệ sẽ được ném khi mảng không thể phù hợp với thế hệ cũ (dễ dàng để kiểm tra), mặc dù toàn bộ đống là đủ lớn. –

+0

@Pacerier: Tôi đã thực hiện một số thử nghiệm và cập nhật câu trả lời của mình một cách đáng kể. Có một cái nhìn! –

1

Nó cho biết thiếu bộ nhớ heap. Có thể có rất nhiều bộ nhớ có sẵn trong các khu vực khác nhưng không có đủ bộ nhớ heap để tạo đối tượng được yêu cầu (có thể là mảng (hoặc) chuỗi đơn giản). Đây là blog hay trên topic này.

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