用JDBC4PreparedStatement填充Java堆

用JDBC4PreparedStatement填充Java堆,java,mysql,hibernate,jpa,playframework-2.0,Java,Mysql,Hibernate,Jpa,Playframework 2.0,我在写剧本!2.3使用Akka进行多线程处理的应用程序。每个线程访问一个MySQL数据库并运行一些计算。每次我运行一组这样的任务时,应用程序的内存占用都会增加,这主要是因为JDBC4PreparedStatement对象永远不会消失。运行几次之后,这些对象占用了超过200MB的内存,很快就会产生一个内存不足错误,调用Sytem.gc()根本不会降低它 我正在使用Hibernate 4.3.0进行持久化,在EntityManager上调用clear()也没有帮助,所以并不是说任何地方都存储了持久

我在写剧本!2.3使用Akka进行多线程处理的应用程序。每个线程访问一个MySQL数据库并运行一些计算。每次我运行一组这样的任务时,应用程序的内存占用都会增加,这主要是因为
JDBC4PreparedStatement
对象永远不会消失。运行几次之后,这些对象占用了超过200MB的内存,很快就会产生一个内存不足错误,调用
Sytem.gc()
根本不会降低它

我正在使用Hibernate 4.3.0进行持久化,在
EntityManager
上调用
clear()
也没有帮助,所以并不是说任何地方都存储了持久化对象。这意味着可能有
Statement
对象在某个地方处于打开状态,但我从不直接与
Statement
对象或
Connection
对象交互,只与JPA的
EntityManager
交互

这是MySQL JDBC或JPA的预期行为吗?如何解决此内存泄漏问题?我不确定在哪里寻找解决方案,不确定这是否是由MySQL、JDBC、JPA或Hibernate实现的。或者可能是游戏的方式!处理JPA


编辑

明确地说,我没有使用
连接
语句
对象,因此没有任何东西可以关闭。下面是一个示例,我从事务中的Play中获取
EntityManager
,执行一些操作,然后事务提交

        JPA.withTransaction( () -> {
            Site site= JPA.em().find(Site.class, siteId);
            site.setDomain("www.stackoverflow.com");
        });

这是预期的行为。您必须告诉mysql连接返回一个游标,而不是通过设置选择完整的集合:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
              java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

根据您的要求,您的特定设置可能会稍有不同,因此可能需要进行一些调整。

正如我在问题中提到的,我没有使用任何
语句
连接
对象;我正在使用JPA接口。我添加了一个编辑来澄清您将不得不使用本机JDBC来避免此位置的JPA行为。您是否检查了相关的SE问题,如和?没有特别看到这些问题。其中的问题只是一次向内存加载太多,而不是任何形式的泄漏。我在处理完持久性缓存后会非常小心地清除它。在这一点上,我甚至经常使用
EntityManager.clear()
,以牺牲速度为代价。