Утечка памяти Java, уничтожить / завершить объект - PullRequest
0 голосов
/ 27 сентября 2010

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

Проблема

Объект Object_XXX довольно сложный, с подключениями к базам данных и другими объектами, заполненными данными из баз данных, а также.

    for(int i=0; i<MAX; i=i+1){
        Class_XXX Object_XXX = new Class_XXX(Arg_1, Arg_2);

        // action with Object_XXX
    }

Теперь, после вызова нескольких методов, Object_XXX также можно отбросить, поскольку для следующего цикла потребуется объект с другими характеристиками (разные массивы, размер массивов, вложенные объекты ...).

Конструктор аналогичен приведенному ниже, а другие классы имеют аналогичный конструктор.

public Class_XXX(Arg_1, Arg_2, DB_Connection){

    try {
        Statement Query_Statement = null;
        ResultSet Query_ResultSet = null;
        String Query_String = null;

        Query_String = "...";
        Query_Statement = DB_Connection.createStatement();
        Query_ResultSet = Query_Statement.executeQuery(SQL);

        while (Query_ResultSet .next()) {
            this.Param_1 = Query_ResultSet .getString("param_1");
    this.Param_2 = Query_ResultSet .getString("param_2");
            ...
    this.Param_n = Query_ResultSet .getString("param_n");
        }
    } catch (SQLException e) {
        System.out.println("SQL Exception: "+ e.toString());
    }
}

Вопросы

Какой подход был бы наиболее правильным в этом случае? а) завершить Object_XXX в конце цикла б) чтобы завершить каждый отдельный объект, который составляет Object_XXX, когда они не используются внутри кода? Лично я предпочел бы а), поскольку я думаю, это позволит сборщику мусора работать без особых проблем с ним

Не могли бы вы также привести пример кода или ссылку?

Спасибо!


Второй раунд:

После ответов, найденных ниже, и просмотра этой другой страницы (http://accu.org/index.php/journals/236),, это шаблон, который я сейчас использую для конструкторов. Слишком рано, чтобы увидеть, работает ли он. По-прежнему есть " exception.toString", но реальный код присваивает переменным стандартные значения в случае исключения и сообщает о действии в журнале.

public Class_XXX(String Object_Name, java.sql.Connection Query_Connection){

    try{ // begin try-catch for Query_Connection
        Statement Query_Statement = Query_Connection.createStatement();
        try { // begin try-finally for Query_Statement
            String Query_String = "SELECT param_1, param_2, ... param_3 FROM table_name WHERE object_name = '" + Object_Name + "'";
            ResultSet Query_ResultSet = Query_Statement.executeQuery(Query_String);
            try { // begin try-finally for Query_ResultSet

                while (Query_ResultSet.next()) {
                    this.Param_1 = Query_ResultSet.getString("param_1");
                    this.Param_2 = Query_ResultSet.getString("param_2");
                    // ...
                    this.Param_n = Query_ResultSet.getString("param_n");
                }

            } finally {
                try { Query_ResultSet.close(); }
                catch (SQLException ex) { System.out.println("Error in Class_XXX constructor - " + ex.toString()); }
            } // end try-finally for Query_ResultSet

        } finally {
            try { Query_Statement.close(); }
            catch (SQLException ex) { System.out.println("Error in Class_XXX constructor - " + ex.toString()); }
        } // end try finally for Query_Statement

    } catch(SQLException ex) {
            System.out.println("Error in Class_XXX constructor - " + ex.toString());
    } // end try-catch for Query_Connection

}

Ответы [ 4 ]

4 голосов
/ 27 сентября 2010

Завершающий объект не удалит его из памяти, если что-то все еще содержит ссылку на него.И если ничто не содержит ссылку, сборщик мусора все равно ее удалит, поэтому финализация здесь не имеет большого смысла.

Если вы испытываете утечку памяти, что-то должно сохранять ссылку на ваши объекты, поэтому они не могутмусор собрал.Я бы посоветовал использовать какой-нибудь профилировщик, чтобы посмотреть, что это такое.

2 голосов
/ 27 сентября 2010

Похоже, вы программист на C ++, привыкший к RAII.

Java не поддерживает RAII с эквивалентной семантикой, такой как C ++, поскольку уничтожение объекта выполняется сборщиком мусора через некоторое время после того, как объект становится недоступным, в отдельном фоновом потоке.Из-за этого вряд ли кто-либо использует метод finalize (который в противном случае был бы эквивалентом деструктора C ++) для освобождения ресурсов.

Для объектов, которые занимают только память, Java не нуждается в RAII, поскольку их память будет автоматически возвращена сборщиком мусора через некоторое время после того, как они станут недоступными.В частности, явное освобождение членов не требуется.

Объекты, управляющие ресурсами, отличными от памяти (например, дескрипторы файлов), или желающие выполнить немедленную очистку, обычно предлагают метод очистки, который должен вызываться явно.Как вы можете видеть из их javadoc, экземпляры Statement и ResultSet являются такими объектами (они ссылаются на ресурсы вне виртуальной машины, которые нужно своевременно освобождать).Типичный шаблон для вызова метода очистки безопасным для исключений образом:

Statement statement = connection.createStatement();
try {
    ResultSet resultset = statement.executeQuery(sql);
    try {
        // read the resultset
    } finally {
        resultset.close();
    }
} finally {
    statement.close();
}

И некоторые вопросы стиля:

  • exception.toString() просто содержит сообщение об исключении.exception.printStackTrace() дополнительно печатает всю трассировку стека.
  • почти каждый программист java следует соглашению, что имена пакетов начинаются со строчной буквы, имена классов - с заглавной буквы, а поля / переменные - строчными.Кроме того, слова обычно разделяются с использованием верблюжьего падежа, а не _.
1 голос
/ 27 сентября 2010

Мальчик, что за конструктор.

Вы выделили довольно много локальных переменных и не показали нам никакого кода, который их выпускает, например,

    Statement Query_Statement = null;
    ResultSet Query_ResultSet = null;

Хотя в любом случае вам не следует вызывать finalize самостоятельно, его вызов здесь в любом случае не поможет, поскольку у него не будет доступа к локальным переменным, объявленным в вашем конструкторе.

Научитесь следовать этой схеме:

final Statement stmt = createStatement( );

try
{
  useStatement( stmt );
}
finally
{
  stmt.close( );
}

Это единственный способ предотвратить утечку ресурсов (не только памяти).

Кроме того, ОЧЕНЬ плохая идея проглотить исключение так, как вы это делаете.

1 голос
/ 27 сентября 2010

Использование финализирующего подхода не рекомендуется. Вам лучше оставить это для сборщика мусора. НО, вы должны освободить вложенные ресурсы (закрыть их, назначить ноль).

...