2012-06-13 2 views
1

Я бегу в OutOfMemoryError на фоне долго работает на Glassfish. Анализ памяти показал, что в момент сброса ошибки 50% кучи предназначено для экземпляров com.mysql.JDBC4ResultSet (28,1%) и com.mysql.jdbc.StatementImpl (22,1%).JDBC кеширование на Glassfish

Мой код структурирован в предположении, что мои объекты JDBC будут собирать мусор после их освобождения, но это, очевидно, не так. Я изначально делал это с помощью JPA, но загрузка памяти взорвалась, поэтому я вернулся к JDBC, но я все еще получаю огромные утечки памяти, состоящие из ссылок на JDBC-операторы & ResultSets.

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

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

@Stateless 
public class WSDFileCollector implements Collector { 

    @PersistenceContext 
    private EntityManager em; 

    @Override 
    @Asynchronous 
    public void run(final CollectorEntity collector) throws SQLException { 

     final Connection connection = em.unwrap(Connection.class); 
     final String table = "tmp_sat_" + collector.getSite().getId(); 
     final String column = "filename"; 
     try { 
      // Create temporary table 
      // Scan files & folders under a given directory. 
      // Load filenames into MySQL Temporary table. 

      final Statement statement = connection.createStatement(); 
      final ResultSet results = statement.executeQuery("SELECT filename FROM temporary_table WHERE filename NOT IN (SELECT filename FROM existing_files"); 
      while (results.next()) { 
       final File file = new File(collector.getPath(), results.getString("filename")); 
       if (file.isFile()) { 
        extractAndSave(file, collector); 
       } 
      } 
     } finally { 
      // Delete temporary table 
     } 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    private void extractAndSave(final File file, final CollectorEntity collector) { 
     final Connection connection = em.unwrap(Connection.class); 
     try { 
      // Begin a transaction 
      // INSERT new file into existing_files 

      // Scan the file, extract data and insert into multiple database tables. 

      // Commit transaction 
     } catch (final SQLException | FileNotFoundException ex) { 
      // Rollback transaction 
     } 
    } 
} 

ответ

2

Как вы развернули соединение с менеджером объекта и, таким образом, полностью взять на себя контроль над ресурсами в ваших руках, вы должны явно закрыть их себе в finally блоке того же try как они были приобретены в соответствии со следующим стандартным идиомом JDBC.

// Declare resources. 
Connection connection = null; 
Statement statement = null; 
ResultSet resultSet = null; 

try { 
    // Acquire resources. 
    connection = getConnectionSomehow(); 
    statement = connection.createStatement(); 
    resultSet = statement.executeQuery(sql); 

    // ... 
} finally { 
    // Close resources in reversed order. 
    if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {} 
    if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {} 
    if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {} 
} 

В противном случае они останутся в открытом состоянии и действительно просачиваются как на сервере, так и на БД.

+0

Ваш на деньги, как всегда BalusC. Я понятия не имел, что ResultSet и Statement необходимо закрыть. Благодарю. – klonq

+0

Добро пожаловать. – BalusC

Смежные вопросы