Куча JVM продолжает увеличиваться. Зачем?

executor = Executors.newScheduledThreadPool(1);
Runnable helloRunnable = new Runnable() {
    public void run() {
        controller2.GetAIntFromDatabase(columblName);
    }
};
executor.scheduleAtFixedRate(helloRunnable, 0, 10, TimeUnit.MILLISECONDS);

эта часть программы генерирует ошибку увеличения кучи памяти.

 controller2.GetAIntFromDatabase(columblName); 

с помощью этой функции я читаю значение int из моей базы данных.

    @Override
    public int GetAIntFromDatabase(String columblName) {
        int stare = 0;
        try{
            String query = "SELECT * FROM stari ORDER BY id DESC LIMIT 1"; 
            PreparedStatement preparedStatement = this.connnection.prepareStatement(query);          
            ResultSet resultSet = preparedStatement.executeQuery();
            if (resultSet.next()){
               stare = resultSet.getInt(columblName);
             preparedStatement.close();            
                resultSet.close();
               return stare;
            }
            preparedStatement.close();            
            resultSet.close();
        }catch (SQLException ex) {
            System.out.println("GetUtilajStare Error: "  + ex);
            return 0;
        }

        return 0;
    }

Это использование памяти кучи Java после 10 минут работы:

используемая память кучи Java в течение 10 минут

Почему моя куча памяти продолжает увеличиваться?

2 ответа

Решение

Вы должны использовать Java 7+ способ закрытия ресурсов, попробуйте с ресурсами.

Оператор try-with-resources является try заявление, которое объявляет один или несколько ресурсов. Ресурс - это объект, который должен быть закрыт после завершения программы. Оператор try-with-resources обеспечивает закрытие каждого ресурса в конце оператора. Любой объект, который реализует AutoCloseable, который включает в себя все объекты, которые реализуют Closeable, может быть использован в качестве ресурса.

public int GetAIntFromDatabase(String columblName) {
    final String query = "SELECT * FROM stari ORDER BY id DESC LIMIT 1";
    try (final PreparedStatement preparedStatement = this.connnection.prepareStatement(query)) {
        final ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            return resultSet.getInt(columblName);
        }
        return 0;
    } catch (SQLException ex) {
        // Do something better than System.out.println(...)
        return 0;
    } 
    return 0;
}

Также вам не нужно явно закрывать результирующий набор, подготовленный оператор делает это так, как он владеет результирующим набором:

Когда Statement объект закрыт, его ток ResultSet Объект, если таковой существует, также закрыт.

Однако, если вы хотите быть параноиком и переборщить, как @MarkRotteveel предлагает в своем комментарии, вы можете добавить в качестве AutoCloseable ресурс также ResultSetи код будет выглядеть так:

public int GetAIntFromDatabase(String columblName) {
    final String query = "SELECT * FROM stari ORDER BY id DESC LIMIT 1";
    try (final PreparedStatement preparedStatement = this.connnection.prepareStatement(query);
         final ResultSet resultSet = preparedStatement.executeQuery()
    ) {
    ...
}

Я никогда не делал этого и никогда не нуждался в этом, и в документации прямо говорится, что в этом нет необходимости, но у некоторых людей возникали проблемы в определенных крайних случаях.

Во втором случае особенно заметно, насколько спасает вас попытка с ресурсами - вам не нужно присваивать переменные null, вам не нужно проверять, были ли открыты какие-либо из них, и даже если один из close() методы выдает исключение, "замкнутая цепочка" не разрывается и close() методы других ресурсов вызываются в любом случае.

Если исключение выдается после открытия preparedStatement и resultSet, они никогда не будут закрыты. Поэтому вы должны использовать finally блок, который всегда будет выполняться.

public int GetAIntFromDatabase(String columblName) {
    int stare = 0;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        String query = "SELECT * FROM stari ORDER BY id DESC LIMIT 1";
        preparedStatement = this.connnection.prepareStatement(query);
        resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            stare = resultSet.getInt(columblName);
            return stare;
        }
    } catch (SQLException ex) {
        System.out.println("GetUtilajStare Error: " + ex);
        return 0;
    } finally {
        if (preparedStatement != null)
            preparedStatement.close();
        if (resultSet != null) 
            resultSet.close();
    }
    return 0;
}
Другие вопросы по тегам