2011-11-18 42 views
5

tôi có chương trình thử nghiệm sau đây:Java: Exception OutOfMemoryError và freeMemory()

public static void main(String[] args) 
{  
    HashMap<Integer, String> hm = new HashMap<Integer,String>(); 
    int i = 1; 
    while(true) 
    { 
     hm.put(i, "blah"); 
     i++; 
     System.out.println("############"); 
     System.out.println("Max mem: " + Runtime.getRuntime().maxMemory()); 
     System.out.println("Total mem: " + Runtime.getRuntime().totalMemory()); 
     System.out.println("Free mem:" + Runtime.getRuntime().freeMemory()); 
    } 
} 

Nếu tôi chạy chương trình này, tôi nhận được đầu ra follwing:

... 

    ############ 
    Max mem: 8060928 

    Total mem: 8060928 

    Free mem:334400 

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
     at java.util.HashMap.addEntry(Unknown Source) 
     at java.util.HashMap.put(Unknown Source) 
     at Test.main(Test.java:14) 

Tại sao tôi nhận được một "OutOfMemoryError "Ngoại lệ mặc dù phương thức freeMemory() trả về rằng có nhiều bộ nhớ trống hơn ??? Nếu có cách nào để sử dụng tất cả các freeMemory()?

Trả lời

0

Dường như số lượng bộ nhớ trống không đủ để chạy JVM.

1

Bạn sẽ nhận được ngoại lệ bộ nhớ ngoài tại điểm mà HashMap cần mở rộng bộ nhớ trong của nó. Yêu cầu cho điều này sẽ lớn hơn bộ nhớ cảm ứng có sẵn.

+0

Nhưng khi tôi sử dụng LinkedList thay vì HashMap, tôi nhận được cùng một vấn đề. Trong bối cảnh thực sự của tôi, tôi muốn đọc 10 triệu bản ghi dữ liệu, mỗi bản ghi là một HashMap và tôi lưu trữ tất cả các HashMaps trong một LinkedList. Và jvisualvm nói với tôi rằng chương trình của tôi có thể sử dụng tối đa. 80GB, nhưng nó chỉ sử dụng 65GB. Tại thời điểm này tôi nhận được ngoại lệ ... – user1053813

+0

@ user1053813, Bạn có thể làm điều này, nhưng bạn sẽ cần phải cung cấp cho ứng dụng của bạn rất nhiều bộ nhớ, nhiều GB tôi nghi ngờ. Bộ nhớ là khá rẻ những ngày này để không phải là một vấn đề. Nếu bạn muốn dữ liệu được lưu trữ hiệu quả hơn, tôi sẽ sử dụng các đối tượng thay vì HashMap. (có thể nhỏ hơn 2-3 lần) Có thể có một số loại rào cản bộ nhớ liên quan đến hệ điều hành ngăn bạn sử dụng hơn 64 GB trong một ứng dụng. Bạn có thể xem xét sử dụng bộ nhớ trực tiếp để lưu trữ dữ liệu, điều này có thể bằng một nửa kích thước của các đối tượng và sử dụng rất ít heap nhưng có nhiều công việc hơn. ;) –

4
  1. Runtime.freeMemory() javadoc nói đó là lợi nhuận "an approximation to the total amount of memory currently available for future allocated objects"

  2. Cách tất cả các cấu trúc làm việc năng động là họ cấp phát bộ nhớ trong khối. Khi HashMap đang đầy, nó không phân bổ thêm không gian cho chỉ một đối tượng nữa. Nó phân bổ một đoạn của một số kích thước. Tôi không biết cách chính xác nó hoạt động trong JVM, nhưng nó có thể cố gắng phân bổ nhiều gấp đôi số lượng bộ nhớ hiện tại nó sử dụng.

4

Lớp HashMap đổi kích thước nhân dịp số lượng mục nhập trong đó tăng lên. Mặc dù bạn đang hiển thị 300 + K miễn phí, điều đó có thể không đủ để xử lý việc thay đổi kích thước của nhóm băm.

void resize(int newCapacity) { 
    Entry[] oldTable = table; 
    int oldCapacity = oldTable.length; 
    if (oldCapacity == MAXIMUM_CAPACITY) { 
     threshold = Integer.MAX_VALUE; 
     return; 
    } 
    // ***possible big allocation here*** 
    Entry[] newTable = new Entry[newCapacity]; 
    transfer(newTable); 
    table = newTable; 
    threshold = (int)(newCapacity * loadFactor); 
} 

Trong một ý nghĩa tổng quát hơn, các yêu cầu chi tiết tốt về bộ nhớ heap (và quy trình tổng thể) không được khuyến nghị trong Java. Có phân bổ nền cũng như các đối tượng trong vùng heap chưa được khai hoang chiếm dung lượng mà bạn có thể không lường trước được. Ngoài ra, bộ thu gom rác sử dụng CPU ngày càng nhiều khi nó tiếp cận một đống đầy đủ. Bạn muốn chạy với nhiều chi phí bộ nhớ cao hơn kích thước phân bổ tối đa dự kiến ​​của bạn.

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