от
У меня есть код, который обращается к базе данных SQLite с использованием JDBC. Я заметил, что каждый раз, когда делается запрос, использование памяти увеличивается - и оно не падает даже после закрытия соединения. Вот что я делаю: 1) Закрытие
PreparedStatement
2) Закрытие
ResultSet
3) Закрытие соединения Вот скриншот анализа heapdump: Он показывает много объектов
java.lang.ref.Finalizer
и много объектов
PreparedStatement
и
ResultSet
. Вот код (он в Scala, но должен быть легко сопоставим с Java):
val conn: Connection = DriverManager.getConnection(url)


// Gets strings by a query like SELECT .. WHERE foo = ?
def getStringsByQuery(query: String, param: String, field: String):Seq[String] = {

    val st = conn.prepareStatement(query)
    st.setString(1, param) //value of foo = ?
    st.setFetchSize(Integer.MAX_VALUE)
    st.setMaxRows(Integer.MAX_VALUE)

    //Holder of results
    var results = collection.mutable.Seq.empty[String]

    val rs: ResultSet = st.executeQuery()

    //add results to holder
    while (rs.next())
      results : = rs.getString(field)

    rs.close() //closing ResultSet
    st.close() //closing PreparedStatement
    results
  }
Вот тест, который я написал, чтобы проверить это:
test("detect memory leak") {

    log.info("Starting in 10 sec")
    Thread.sleep(10.seconds.toMillis)

    //Calls a method over and over to see if there's a memory leak or not..
    (1 to 1000).par.foreach(i => {
      val randomWord = getRandomWord() //this produces a random word
      val sql = "SELECT foo FROM myTable where bar = ?"
      val results = getStringsByQuery(sql, randomWord, "bar")
    })

    conn.close() //close the connection
    log.info("Closed conn, closing in 30 sec")

    Thread.sleep(1.minutes.toMillis)
  }
Когда я запускаю тест - использование памяти постоянно увеличивается с 24,6 ГБ до 33 ГБ и никогда не снижается (даже если ResultSet PreparedStatement закрываются), и даже в конце, когда соединение закрывается и поток спит в течение 1 минуты - использование памяти по-прежнему не снижается. Кто-нибудь знает, что здесь происходит? Буду признателен за любую помощь.              

Ваш ответ

Отображаемое имя (по желанию):
Конфиденциальность: Ваш электронный адрес будет использоваться только для отправки уведомлений.

1 Ответ

0 голосов
от
Мы запускаем sqlite-jdbc в производственной среде, и мы заметили подобное поведение при проверке дампов кучи. Эти объекты находятся только в куче, потому что они еще не прошли через сборщик мусора. В смысле https://blog.nelhage.com/post/three-kinds-of-leaks/ это «утечка памяти типа 2», в которой объекты были распределены и живут немного дольше, чем вы ожидаете , Проблема, которую это вызвало для нас, заключается в том, что машины будут сохранять память в куче Java в течение неожиданно длительного периода времени, что приводит к нехватке памяти во время пиковых запросов. Мы сделали несколько разных вещей, чтобы эти объекты собирались чаще. Уменьшите общий размер кучи Java. Это гарантирует, что сборщик мусора видит больше необходимости очищать эти объекты. Наша рабочая нагрузка на SQLite очень высока, поэтому лучше, чтобы машинная память перемещалась в память вне кучи через JNI, а не выделялась в куче Java. Настройте сборщик мусора G1GC, чтобы выделить больше кучи для newgen, так как эти объекты обычно очень недолговечны. (Https://www.oracle.com/technetwork/articles/java/g1gc-1984535.html) Увеличьте количество журналов сборщика мусора и запустите их через службу типа GCEasy (https://gceasy.io/), чтобы точно понять, какие типы сборок мусора выполнялись для дальнейшей настройки. Они могут не соответствовать вашему варианту использования, но вот некоторые варианты, которые вы можете рассмотреть в зависимости от того, с чем вы столкнулись.     
...