我在使用 Spring、Hibernate 和 JPA 的 Web 应用程序时遇到了一些问题。问题是非常高的内存消耗,它随着时间的推移而增加,而且似乎永远不会减少。它们很可能源于对 EntityManager 的错误使用。我已经四处寻找,但我还没有找到确定的东西。
我们正在使用 DAO,它们都扩展了以下 GenericDAO,其中我们唯一的 EntityManager 被注入:
public abstract class GenericDAOImpl<E extends AbstractEntity<P>, P> implements
GenericDAO<E, P> {
@PersistenceContext
@Autowired
private EntityManager entityManager;
[...]
使用通用 DAO 是因为它具有通过 ID 获取实体的方法等,这在所有约 40 个 DAO 中实现起来会很痛苦。
EntityManager 通过以下方式配置为 Spring bean:
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManager" factory-bean="entityManagerFactory"
factory-method="createEntityManager" scope="singleton" />
我认为最大的问题是使用这个共享的 EntityManager 来处理所有事情。在服务类中,我们将 @Transactional 注释用于需要事务的方法。这会从我读取的内容中自动刷新 EntityManager,但与清除不同,所以我猜这些对象仍在内存中。
我们注意到每天在数据库中每次自动导入数据后内存都会增加(大约 7 个文件,每个文件 25k 行,其中创建了很多链接对象)。而且在正常运行期间,当检索大量数据时(假设一次请求 100-200 个对象)。
任何人都知道我该如何改善目前的情况(因为此时情况有点糟糕......)?
编辑:在已部署的应用程序上运行了探查器,这就是它发现的:
One instance of "org.hibernate.impl.SessionFactoryImpl" loaded by "org.apache.catalina.loader.WebappClassLoader @ 0xc3217298" occupies 15,256,880 (20.57%) bytes. The memory is accumulated in one instance of "org.hibernate.impl.SessionFactoryImpl" loaded by "org.apache.catalina.loader.WebappClassLoader @ 0xc3217298".
这大概是EntityManager没有清除吧?