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

#java #eclipse #compiler-warnings #resource-leak

#java #eclipse #компилятор-предупреждения #утечка ресурсов

Вопрос:

Я не могу понять, почему компилятор предупреждает меня об утечке ресурсов ( Resource leak: 'conn' is not closed at this location ) в следующем коде:

     Connection conn = null;
    try {
        conn = DatabaseConnectionPool.getConnectionFromPool();
        // Some code
        try {
            // Other code
        } catch (final SomeException e) {
            // More code
            throw e; // Resource leak: 'conn' is not closed at this location
        }

    } catch (final SQLException | OtherExceptions e) {
        // Some more code
    } finally {
        try {
            // Another bunch of code
        } finally {
            DatabaseConnectionPool.freeConnection(conn);
        }
    }
 

Обратите внимание, что если я напишу это так

     Connection conn = null;
    try {
        conn = DatabaseConnectionPool.getConnectionFromPool();
        // Some code
        try {
            // Other code
        } catch (final SomeException e) {
            // More code
            throw e;
        } finally {
            DatabaseConnectionPool.freeConnection(conn);
        }

    } catch (final SQLException | OtherExceptions e) {
        // Some more code
    } finally {
        // Another bunch of code
    }
 

предупреждение исчезло.

Комментарии:

1. Это не предупреждение компилятора. Вы используете инструмент для создания этого предупреждения, и, скорее всего, это ошибка в инструменте.

2. Я думаю, что блок finally является ключевым

3. @PeterLawrey Это встроенный компилятор Eclipse Java, так что это действительно предупреждение компилятора. Но я думаю, вы правы, это ошибка в этом компиляторе.

4. final SQLException | OtherExceptions e — что это значит? (может быть, мне следует изучить не только последнюю версию C , но и последнюю версию java; .. коды быстро развиваются ..)

5. @m0skit0 он рассматривает его как ближайший общий родительский элемент, который может быть RuntimeException или Exception. Он был добавлен в Java 7 в 2011 году.

Ответ №1:

Компилятор довольно дамп. Вероятно, он не может знать, что DatabaseConnectionPool.freeConnection(conn) вызовет close conn . Я не уверен, почему второй пример не вызывает это предупреждение, но, вероятно, функция просто не совсем идеальна и может давать ложные отрицательные результаты. По сути, любой ресурс должен быть закрыт путем вызова его close метода непосредственно в том месте, где получен ресурс; это единственный способ, которым компилятор может выяснить, что вы хотите его закрыть, это не относится к межпроцедурному анализу, чтобы проверить, вызывает ли вызываемая функция close .

В java7 вам следует рассмотреть возможность использования инструкции try-with-resource; это рекомендуемый способ обработки любых ресурсов, т. Е.:

 try(Connection conn = ...){
   // Do something with conn

   // No close necessary here, done implicitly by the try statement
}
 

Весь ваш шаблон закрытия соединения путем вызова метода, отличного от close , кажется мне ошибочным (он работает, но я бы настоятельно не рекомендовал его использовать): любой ресурс должен иметь возможность закрываться при вызове close . Если ваш ресурс требует DatabaseConnectionPool.freeConnection вызова для его закрытия, вы нарушаете контракт ресурсов java. Если вы используете оператор try-with-resource , у вас все равно нет выбора: вызовет оператор, close а не ваш метод.

Комментарии:

1. Он определенно знает DatabaseConnectionPool.freeConnection(conn) вызовы close , вот почему во втором примере нет предупреждения. Я думаю, что его логика проверки просто не может обрабатывать вложенные try . И спасибо за попытку с ресурсом, я читал об этом, но совершенно забыл его использовать (я все еще в основном ориентирован на Java-6).

2. @m0skit0: То, что второй пример работает, не означает, что он это знает. Второй пример может быть ложноотрицательным. Но ваше предположение также может быть правдой.

3. Ну, это работает, чтобы объяснить оба случая, в то время как ваш не может объяснить второй случай; Я пока буду придерживаться его. Спасибо за вашу помощь и напоминание о try-with-resource!

4. Я поддерживаю ваш ответ, но я не могу принять его, поскольку, на мой взгляд, это неправильное объяснение. Комментарий Питера Лори — самый близкий правильный ответ.

5. @m0skit0: Что происходит, когда вы удаляете close вызов в своем DatabaseConnectionPool.freeConnection методе? Выдает ли второй пример также предупреждение? Если это произойдет, то вы правы; если нет, то я прав.