2012-04-17 5 views
8

Tôi nhận được lỗi OutOfMemory hàng ngày trong một phiên bản mới của đơn đăng ký của mình. Chúng tôi có 1,5 GB đống phân bổ cho Tomcat.JPA Hibernate DBCP Tomcat OutOfMemory

Sử dụng máy phân tích Memory Eclipse (http://www.eclipse.org/mat/) Tôi đã nhận như sau dưới Luỹ kế Shortest Path

org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList$Listable @ 0xa1566cc8 
    _head org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList @ 0xa1566ca8 
     _pool org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool @ 0xa1566c38 
     connectionPool org.apache.tomcat.dbcp.dbcp.BasicDataSource @ 0xa1566980 
      dataSource org.springframework.orm.jpa.JpaTransactionManager @ 0xa0b01760 
        <Java Local> java.lang.Thread @ 0xa4005900 ajp-8141-5 Thread 

kiểm tra sâu hơn về điều này cho thấy rất nhiều các chuỗi trùng lặp đó là các truy vấn Hibernate. Trên màn hình chính của ứng dụng của tôi, tôi tải danh sách tài liệu. Một bản sao của truy vấn tồn tại 8,241 lần trong bãi chứa đống.

Tôi cũng nhận thấy rằng 1 GB đống được chứa trong org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool. Truy vấn tài liệu này đang tải dữ liệu nhị phân tài liệu. Tài liệu đang tải khoảng 1MB. Điều này làm cho tôi nghi ngờ rằng Danh sách không được dọn dẹp bởi bộ thu gom rác. Chúng tôi sẽ loại bỏ dữ liệu không cần thiết khỏi truy vấn nhưng nó vẫn lo ngại rằng các đối tượng đang bám sát.

Tôi đang sử dụng JPA, Hibernate và Spring. Tôi đang sử dụng @Transactional(readOnly=true) trên phương thức nhận danh sách tài liệu. Đây là cấu hình Spring của tôi cho nguồn dữ liệu:

<jee:jndi-lookup jndi-name="jdbc/MyDB" id="myDataSource"/> 

    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 

     <property name="dataSource" ref="myDataSource"/> 
     <property name="persistenceUnitName" value="WebPU"/> 
     <property name="persistenceProvider"> 
      <bean class="org.hibernate.ejb.HibernatePersistence" /> 
     </property> 
     <property name="jpaVendorAdapter"> 
      <bean 
       class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="database" value="SQL_SERVER" /> 
       <property name="showSql" value="false" /> 
       <property name="generateDdl" value="false" /> 
      </bean> 
     </property> 

    </bean> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="myEmf" /> 
    </bean> 

Tôi đang sử dụng Tomcat để cung cấp kết nối tổng hợp. Đây là cấu hình của tôi:

<Resource auth="Container" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" initialSize="20" 
    logAbandoned="true" maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/MyDB" password="pass" poolPreparedStatements="true" removeAbandoned="true" removeAbandonedTimeout="30" 
    type="javax.sql.DataSource" 
    url="jdbc:sqlserver://devmssql;databaseName=MY_DEV;responseBuffering=adaptive;port=1444" 
    username="user"/> 

Lớp dịch vụ có @Transactional. Truy vấn JPA của tôi trông giống như sau:

public List<Document> getDocs(int cId, int lId, int ldId) { 
     CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder(); 
     CriteriaQuery<Document> select = queryBuilder.createQuery(Document.class); 

     Root<Document> from = select.from(Document.class); 

     select.where(
       queryBuilder.and(queryBuilder.equal(from.get(Document_.cId), cId), 
       queryBuilder.equal(from.get(Document_.lId), lId), 
       queryBuilder.equal(from.get(Document_.ldId), ldId))); 




     TypedQuery<Document> tq = getEntityManager().createQuery(select); 

     final List<Document> rl = tq.getResultList(); 

     return rl; 
    } 

Tôi nên tìm gì để giúp xác định nguyên nhân gốc rễ của rò rỉ bộ nhớ? Có các cài đặt DBCP, Hibernate hoặc Spring có thể đóng góp cho điều này không? Có bất kỳ điều gì bạn nhận thấy trong mã truy vấn JPA có thể đang đóng góp không?

+0

getEntityManager() được triển khai như thế nào? EntityManager được tiêm với chú thích @PersistenceContext? – samlewis

+0

Có. Mùa xuân đang tiêm, điều này không chạy trong một máy chủ JavaEE. Chúng tôi đang sử dụng Tomcat. – Allan

Trả lời

0

Cố gắng xóa bộ nhớ cache EntityManager trước khi bạn trở về từ phương thức. Đầu tiên gọi phương thức EntityManager.flush() và sau đó clean(). Điều này có thể giúp nếu EntityManager của bạn "sống" lâu và nó được sử dụng bởi nhiều hoạt động cơ sở dữ liệu.

Nếu bạn sử dụng Spring, bạn có thể từ bỏ việc sử dụng Hibernate cho tình huống có vấn đề và đi với JDBC đơn giản. Spring cho chúng ta JDBCTemplate hoạt động dễ dàng với các truy vấn và cũng cung cấp giao diện quản lý giao tác chung, vì vậy bạn có thể kết hợp các hoạt động Hibernate với các truy vấn JDBC.

1

Tôi thực sự khuyên bạn nên sử dụng VisualVM hoặc jProfiler để xác định rò rỉ. IMHO của nó là cách dễ nhất.