Java SQL查询内存泄漏

时间:2012-04-22 11:38:37

标签: java memory heap

我有一个应用程序迭代一定数量的resultSets并查询来自不同表的每一行的附加信息。

粗糙的结构是这样的:

public void main(String[] args) {
    ResultSet result = database.connection.createStatement()
                           .executeQuery("SELECT * FROM entities");
    ArrayList<Entity> entities = new ArrayList<Entity>();
    while (result.next() {
        Entity entity = EntityFactory.createById(result.getInt("id"));
        entities.add(entity);
    }
}

// EntityFactory
public static Entity createById(int id) {
    StringBuilder sql = new StringBuilder("SELECT * FROM sampling_data WHERE id = ")
                            .append(id);
    ResultSet result = database.connection.createStatement()
                            .executeQuery(sql.toString());
    result.first();
    EntityData data = new EntityData(25);

    for (int sample = 1; sample <= 25; sample++) {
        String sample_R = new StringBuilder("sample_")
                              .append(sample).append("_R").toString();
        String sample_G = new StringBuilder("sample_")
                              .append(sample).append("_G").toString();
        String sample_B = new StringBuilder("sample_")
                              .append(sample).append("_B").toString();

        int r = resultSet.getInt(sample_R);
        int g = resultSet.getInt(sample_G);
        int b = resultSet.getInt(sample_B);

        data.add(r, g, b);
    }

    return new Entity(data);
}

导致OutOfMemoryException。

如何使循环(或整个方法)更节省内存?

3 个答案:

答案 0 :(得分:0)

从代码的一瞥看起来有点难以理解,但我认为它与完全取出的行太多有关。

您应该在Statement上使用setFetchSize(int rows),并且行数合理(可能为100行)。

    private static int FETCH_SIZE = 100;
    ...
    Statement stmt = databaseConnection.createStatement()
    stmt.setFetchSize();
    ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data");

答案 1 :(得分:0)

  

似乎getInt()方法在执行时会占用大量内存   在循环中。

这是不正确的。 getInt()导致您的问题没有什么特别之处。

您的架构打破了关系数据库的第一个常规形式。看到sample_1_R, sample_1_G, sample_1_B也让我质疑你的其他决定。这显然是1:m关系。同样适用于像25这样的魔术数字。

我想知道你为什么要使用String builder和int来做所有的事情。我将这些RGB值封装到一个有意义的对象中,如java.awt.Color

我们在这里谈论了多少数据?

25*3*32*2500 ~ 5.7 MB

这对你的2500行并不多,每行有75个整数值。还有一些其他事情正在发生,你的代码并不清楚。

更新

您在此代码中犯了经典的(n+1)查询错误。您获得所有实体,然后循环它们以获取RGB值。我建议你做一个JOIN并立即把它们全部带回来。这可能无法解释您的记忆问题,但这是一个问题。

在查询RGB值时重复建立列名称。这完全是浪费。在数组中创建static final String个实例。

答案 2 :(得分:0)

最大的问题是(我认为)createById没有关闭结果集和语句。 此外,没有nx1查询是有意义的。

    try {
        Statement stmt = database.connection.createStatement();
        ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data d"
            + " WHERE EXISTS(SELECT * FROM entities e WHERE e.id = d.id)");
        List<Entity> entities = new ArrayList<Entity>();
        while (result.next()) {
            Entity entity = EntityFactory.createById(result);
            entities.add(entity);
        }
        result.close();
        stmt.close();
    } catch (SQLException ex) {
        Logger.getLogger(Test1.class.getName()).log(Level.SEVERE, null, ex);
    }

// EntityFactory
public static Entity createById(ResultSet resultSet) {
    EntityData data = new EntityData(25);
    for (int sample = 1; sample <= 25; sample++) {
        String sample_R = new StringBuilder("sample_").append(sample).append("_R").toString();
        String sample_G = new StringBuilder("sample_").append(sample).append("_G").toString();
        String sample_B = new StringBuilder("sample_").append(sample).append("_B").toString();
        int r = resultSet.getInt(sample_R);
        int g = resultSet.getInt(sample_G);
        int b = resultSet.getInt(sample_B);

        data.add(r, g, b);
    }

    return new Entity(data);
}