【问题标题】:Java deque / prepared statement memory leakJava双端队列/准备好的语句内存泄漏
【发布时间】:2009-10-18 10:59:29
【问题描述】:

以下一段代码会产生内存泄漏,知道哪一部分吗?

1)

private Deque<Snapshot> snapshots = new LinkedList<Snapshot>();

Iterator<Snapshot> i = world.getSnapshots().descendingIterator();
    while (i.hasNext()) {
        Snapshot s = i.next();
        if (curTime - s.getTimestamp() > 60000) {
            i.remove();
        } else {
            break;
        }
    }

2)

public static void initilizePreparedStatements() {
        try {
            insertNewReportRow = Instance.getWorld().getDB().getConnection().prepareStatement("INSERT INTO `rsca2_reports` (`from`, `about`, `time`, `reason`, `snapshot_from`,`snapshot_about`,`chatlogs`, `from_x`, `from_y`, `about_x`, `about_y`) VALUES(?,?,?,?,?,?,?,?,?,?,?)");
        } catch (SQLException e) {
            e.printStackTrace();
            Logger.error(e);
        }
    }
    public synchronized static void submitReport() {
        /*removed*/
            try {
                    insertNewReportRow.setLong(1, from);
                    insertNewReportRow.setLong(2, about); 
                    insertNewReportRow.setLong(3, time); 
                    insertNewReportRow.setInt(4, reason);
                    insertNewReportRow.setString(5, snapshot_from);
                    insertNewReportRow.setString(6, snapshot_about);
                    insertNewReportRow.setString(7, chatlog);
                    insertNewReportRow.setInt(8, f.getX());
                    insertNewReportRow.setInt(9, f.getY());
                    insertNewReportRow.setInt(10, a.getX());
                    insertNewReportRow.setInt(11, a.getY());
                    insertNewReportRow.executeUpdate();
                } catch (SQLException e) {
                    e.printStackTrace();
                    Logger.error(e);
                } 
            }

【问题讨论】:

  • 只看问题中的小 sn-p 就知道有太多未知数 - 而且 sn-ps 甚至不是完整的代码。也许您可以提供更多信息。
  • 我减少了 sn-ps 以仅包含所需的最低限度的内容。快照类: public Snapshot(Player owner) { this.owner = owner; this.eventTime = System.currentTimeMillis(); } public long getTimestamp() { return eventTime; } 如果还有什么不清楚的地方,请询问,以便我解释。

标签: java database memory memory-leaks prepared-statement


【解决方案1】:

我的猜测是 Instance.getWorld().getDB().getConnection() 在那里你得到一个连接并且只存储对它创建的准备好的语句的引用。 这意味着当您的代码使用准备好的语句完成并且(假设它来自连接池)连接池不会回收连接时,您不会释放连接,但它会在其映射中保留对它的引用。

【讨论】:

  • 代码永远不会用准备好的语句完成,它会在每次发送新报告时不断重复使用。在准备好的语句上执行 executeUpdate() 后,它是否准备好重新- 立即使用?还是我应该以某种方式清洁它?
  • 我的意思是您使用 .getConnection() 检索的连接对象永远不会被释放。当不再使用准备好的语句时,应该释放连接。由于方法是静态的,这可能是该过程的结束。如果这是 Web 应用程序的一部分,并且连接来自应用服务器的连接池,那么您就会泄漏。
  • 谢谢,这似乎是问题所在。
【解决方案2】:

根据实现,来自迭代器的breaking 可能会导致迭代器无法完成自身并阻止自身释放绑定的资源,从而导致内存泄漏。也有可能你永远不会清理你的双端队列,这会导致大小随着时间的推移线性增长。

【讨论】:

  • 我会试试的。不过,双端队列已正确清理。
  • 旁注,我将如何实现必须中断的降序循环?
  • Esko,你能提供一个来源吗?我从来没有听说过。当然,我很想听听 Peeter 关于彻底打破的问题的答案。
  • CPerkins: 是的,也不是,Java 的默认迭代器工作正常,但是我知道一些定制的迭代器如果没有正确“完成”就会导致这类问题。我(好吧,我的一个朋友)遇到的实际案例是使用一些流行的 ORM 映射工具,但我不记得是哪一个,因此目前无法提供链接作为可靠证据。
  • 彻底打破,假设迭代器期望完全迭代,这是一种资源浪费,我所能想到的就是有一个单独的布尔值来控制实际的读取操作,如果发生“中断”布尔值被翻转,迭代器的其余部分被读取,而不用做任何其他事情。
猜你喜欢
  • 2015-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-16
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
相关资源
最近更新 更多