čtvrtek 26. ledna 2006

JDBC memory leak za 5,50-

Je libo si dát malý, únik paměti, který ve výsledku povede k pádu aplikace na java.lang.OutOfMemory? Budeme potřebovat tyto ingredience:

  • kód pracující s databází přes JDBC
  • poolování databázových připojení

To nejdůležitější ovšem představuje následující konstrukce

PreparedStatement pstmt = null;
try {
 
Connection con = //ziskej DB connection z poolu
 
pstmt = con.prepareStatement("select ...");
  
 
//udelas dootaz, zpracujes bysledky
  //a pak vytvoris novy statement, bez toho
  //aniz by si uzavrel ten predchozi

 
pstmt = con.prepareStatement("select ...");

} finally {
 
//ve finally sice zaviras statement,
  //ale to se jedna samozrejme az o tu
  //druhou instanci
 
DatabaseUtils.closeStatement(con, pstmt);
}

Vysvětlím proč k tomu memory leaku dochází, protože to není možná na první pohled patrné. I když je proměnná pstmt lokální a zdá se, že by garbage collector mohl z ní referencovaný objekt uklidit, není tomu tak. Statement je totiž ještě referencován z databázového připojení (con).

Protože jsou databázová připojení poolovaná, tak nezavřené statementy nich dohnívají do té doby, dokud nezaberou tolik paměti, že dojde k java.lang.OutOfMemory. Alespoň takovou zkušenost jsem udělal s Oracle JDBC driverem.

No a na závěr připomenu, že nejlepší ochranou je prevence třeba pomocí toho, že starost o statement objekt necháte někomu jinému viz Návrhový vzor Template method a jeho aplikace v prostředí JDBC