2008-10-20 48 views
5

Tôi là một lập trình viên C++ và tôi đang chơi xung quanh với java sau khi tìm JPA cho một vài ứng dụng hiện tại của tôi là một vị thần gửi. Tôi đã không tiếp xúc với java từ trường đại học và tôi đang gặp vấn đề khi hết dung lượng. Tôi đang sử dụng mã dưới đây như là một phần chính của một thử nghiệm không nghiêm trọng về jdbc/jpa/lucene nhưng tôi tiếp tục nhận ngoại lệ ngẫu nhiên OutOfMemory.quản lý bộ nhớ java

 EntityManager em = emf.createEntityManager(); 
     Query q = em.createQuery("select p from Product p" + 
      " where p.productid = :productid"); 
     Connection con = DriverManager.getConnection("connection string"); 
     Statement st = con.createStatement(); 

     IndexWriter writer = new IndexWriter("c:\\temp\\lucene", new StandardAnalyzer(), IndexWriter.MaxFieldLength.LIMITED); 

     ResultSet rs = st.executeQuery("select productid from product order by productid"); 
     while (rs.next()) { 
      int productid = rs.getInt("PRODUCTID"); 
      q.setParameter("productid", productid); 
      Product p = (Product)q.getSingleResult(); 

      writer.addDocument(createDocument(p)); 
     } 

     writer.commit(); 
     writer.optimize(); 
     writer.close(); 

     st.close(); 
     con.close(); 

tôi sẽ không gửi tất cả các createDocument nhưng tất cả nó làm là khởi tạo một org.apache.lucene.document.Document mới và bổ sung thêm các lĩnh vực thông qua add (mới Dòng ...) vv Có khoảng 50 các trường trong tổng số và hầu hết là các chuỗi ngắn (< 32 ký tự).

Trong tính mới của tôi là có điều gì đó hoàn toàn ngu ngốc tôi đang làm (hay không) có thể khiến mọi thứ không bị GC?

Có các phương pháp hay nhất liên quan đến quản lý bộ nhớ java và đánh dấu vào GC không?

Trả lời

3

Tôi không thấy bất kỳ điều gì rõ ràng không đúng chỗ. Nếu bạn đang làm việc với một cơ sở dữ liệu rất lớn, bạn có thể thử tăng kích thước heap của mình bằng cách sử dụng tùy chọn -Xmx n trong lời gọi JVM của bạn. Điều này thường không phải là giải pháp tốt nhất - chỉ làm với điều này khi bạn biết kích thước thiết lập làm việc của bạn thực sự lớn hơn kích thước heap mặc định.

Bạn có đang sử dụng bất kỳ cấu trúc dữ liệu phức tạp nào không? Nếu bạn có tham chiếu vòng tròn giữa các đối tượng, bạn có thể ngăn chặn bộ thu gom rác làm sạch các đối tượng không thể truy cập được. Nếu bạn có bất kỳ cấu trúc dữ liệu viết tay nào, hãy đảm bảo rằng bạn bỏ trống một cách rõ ràng các tham chiếu đến các đối tượng được xóa thay vì làm một cái gì đó như giảm một biến kích thước.

+1

GC không có vấn đề với tham chiếu vòng tròn, các đối tượng sẽ vẫn bị xóa. Tôi không chắc chắn tôi hiểu những gì bạn có nghĩa là bằng cách rõ ràng null ra tham chiếu đến các đối tượng. Làm thế nào khác bạn sẽ loại bỏ chúng? – Robin

+0

Cách khác để xóa chúng là cho phép chúng vượt quá phạm vi. Thiết lập rõ ràng các tham chiếu đến null là cho sự kết hợp của các đối tượng humongous và các vòng lặp dài, nơi tham chiếu đối tượng sẽ được lưu giữ trong bộ nhớ trong một thời gian dài. – gnud

0

Có bao nhiêu mục trong tập hợp kết quả của bạn? Nếu có đủ bản ghi, bạn sẽ sử dụng hết bộ nhớ, vì không có rác nào được thu thập trong trường hợp này vì bạn đang làm một tài liệu hướng dẫn cho người viết, nó sẽ giữ một tham chiếu đến tất cả các tài liệu bạn đang tạo.

2

Vâng ...

kinh nghiệm lâu với Java và cơ sở dữ liệu (an example post Postgressql mysql oracle khác biệt>) đã dạy tôi rằng các trình điều khiển JDBC chúng tôi sử dụng trong thực hiện công việc này thường xuyên có vấn đề.

Tôi có một đoạn mã cần duy trì kết nối với cơ sở dữ liệu 24/7 và do rò rỉ bộ nhớ trình điều khiển, JVM sẽ luôn bị nghẹn tại một số điểm. Vì vậy, tôi đã viết mã để bắt ngoại lệ cụ thể được ném và sau đó thực hiện hành động ngày càng quyết liệt, bao gồm việc xóa kết nối và kết nối lại và thậm chí khởi động lại JVM trong tuyệt vọng, không có gì làm việc để xóa hoàn cảnh sự cố. Thật là một PAIN phải viết nó, nhưng nó đã hoạt động cho đến khi nhà cung cấp DBMS ra mắt với một trình điều khiển JDBC mới không gây ra vấn đề ... Tôi thực sự chỉ để lại mã tại chỗ, chỉ trong trường hợp!

... Vì vậy, nó có thể là không có gì bạn đang làm.

Lưu ý rằng việc gọi bộ thu gom rác là một trong những chiến lược tôi đã sử dụng, nhưng số liệu cho thấy ít khi được giúp đỡ.

Ngoài ra, có thể không rõ ràng, nhưng ResultSets duy trì kết nối liên tục với chính cơ sở dữ liệu, trong nhiều trường hợp (trừ khi được đặt cách khác) hai chiều, ngay cả khi bạn chỉ đọc. Và, một số trình điều khiển JDBC cho phép bạn yêu cầu kết nối một chiều nhưng nói dối và trả về một hướng hai chiều! Hãy cẩn thận với điều này!

Vì vậy, thực hành tốt để dỡ bỏ các đối tượng ResultSet của bạn thành các đối tượng khác để giữ các giá trị và thả các đối tượng ResultSet càng sớm càng tốt.

Chúc may mắn. RTIII

0

Java duy trì một số vùng nhớ bộ nhớ khác nhau, và chạy ra khỏi bất kỳ một trong số chúng có thể gây ra sự sợ hãi OutOfMermoryException. Sự cố phân bổ bộ nhớ của Hệ điều hành cũng có thể biểu hiện dưới dạng OOM.

Bạn sẽ thấy dấu vết ngăn xếp chi tiết - hoặc có thể là tệp kết xuất lỗi trong thư mục của ứng dụng - điều này có thể cung cấp thêm manh mối về vấn đề.

Nếu bạn sử dụng một trình lược tả phong nha - JVisualVM đi kèm với Sun Java 6 JDK gần đây có thể là đủ - bạn có thể xem tất cả các hồ khác nhau và xem những cái nào đang cạn.

2

Có thể bạn đang hết dung lượng cho Thế hệ vĩnh viễn. Kiểm tra xem stack trace của bạn có chứa một cái gì đó giống như java.lang.OutOfMemoryError: PermGen

Bạn có thể tăng không gian cho thế hệ này với tham số này cho JVM: -XX: MaxPermSize = 128

Đối tượng trong thế hệ vĩnh viễn không được xem xét trong khi thu gom rác thải. Hãy xem this page from sun để tìm hiểu thêm về thu thập rác và các thế hệ đối tượng khác nhau trong JVM.

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