繁体   English   中英

Java SQL 查询内存泄漏

[英]Java SQL query memory leak

我有一个应用程序,它遍历大量 resultSet 并查询不同表中每一行的附加信息。

大致的结构是这样的:

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。

如何使循环(或整个方法)的内存效率更高?

从代码的一瞥中很难判断,但我认为这与总共提取的行太多有关。

您应该在具有合理行数(可能为 100)的Statement上使用setFetchSize(int rows ) 。

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

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

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

您的架构打破了关系数据库的第一范式。 看到sample_1_R, sample_1_G, sample_1_B让我质疑你的其他决定。 这显然是1:m关系。 像 25 这样的神奇数字也是如此。

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

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

25*3*32*2500 ~ 5.7 MB

这对于您的 2500 行来说并不多,每行都有 75 个整数值。 从您的代码中还不清楚正在发生的其他事情。

更新:

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

当您查询 RGB 值时,您会反复构建列名称。 那完全是浪费。 使它们成为数组中的static final String实例。

最大的问题是(我认为)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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM