views:

402

answers:

2

One of the following pieces of code generates a memory leak, any idea which part?

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);
             } 
            }
+1  A: 

Depending on implementation, breaking from iterator may cause the iterator to not complete itself and prevent itself from freeing tied resources and thus causing a memory leak. It's also possible you never clean your Deque either which causes linear growth in size over time.

Esko
I'll try that. The deque is properly cleaned though.
Peeter
Side comment, how would I implement a descending loop where I have to break?
Peeter
Esko, can you provide a source for that? I've never heard it. And of course, I'd love to hear an answer for Peeter's question about breaking cleanly.
CPerkins
CPerkins: Yes and no, Java's default iterators work properly, however I do know for a fact that some custom made iterators cause exactly this kind of problems if they're not "finished" properly. The actual case I(well, a buddy of mine) hit this was with some popular ORM mapping tool but I can't remember which one so can't provide a link as solid proof at this time.
Esko
Breaking cleanly, that's a resource-wasting one assuming the iterator expects to be iterated in full, all I can think of is having a separate boolean which controls the actual reading operation and if "break" occurs that boolean is flipped and the rest of the iterator is read through without doing anything else with it.
Esko
Ahh, that makes more sense. Thanks. For the breaking cleanly problem then, I think the answer would be to either use the Java default iterators, or to insist that any custom iterators provide a cleanup method.
CPerkins
I'm using the default Deque reverse iterator.
Peeter
+3  A: 

My guess would be it's Instance.getWorld().getDB().getConnection() where you get a connection and only store a reference to the prepared statement it creates. This means you do not free the connection when your code is done with the prepared statement and the (assuming it comes from a connection pool) connection pool does not recycle the connection, but it will keep a reference to it in its maps.

rsp
The code is never done with the prepared statement, it keeps on getting re-used each time a new report is sent in. After performing executeUpdate() on a prepared statement, is it ready to be re-used right away? Or should I clean it somehow?
Peeter
I meant the connection object that you retrieve using .getConnection() is not freed ever. When the prepared statement is not used anymore the connection should be freed. As the methods are static this could be the end of the process. If this is part of a web-application and the connection comes from the app-servers' connection pool, you leak.
rsp
Thanks, that seemed to be the problem.
Peeter