Minnesläckage i Valencia
Jag var ute och gick med hunden en tidig morgon och min chef ringde på mobilen:
God morning Jens, we need you in Valencia. There is a client with a severe hard-to-find memory leak in their business-critical application.
Jag skyndade tillbaka hem och bokade in mig på nästa flyg från Stockholm till Valencia i östra Spanien. Det hade blivit sen eftermiddag när jag väl var framme hos kunden.
Under den här tiden jobbade jag som professional services consultant för ett startup företag i San Francisco och var deras goto-man i Stor-Britannien och Central-Europa. Vår produkt handlade om monitorering/övervakning i realtid av stora Java system.
Efter en kort introduktion installerade jag vår analys-programvara (Wily Introscope) och började undersöka deras system. Det var då de sade något som väckte min nyfikenhet.
We already know that there are many exceptions in our system. So, do not bother looking into that. Just find the memory leakage, and we can take it from there.
Jag höll inne med mina synpunkter på detta och kartlade systemet vidare. Det hade blivit sen kväll och vi startade ett last-test, som fick köra över natten.
Nästa morgon sammanställde jag mätvärden jag förberett kvällen innan och det såg ut så här.
Bilden visar tre mätvärden med samma tidsaxel. Överst är Java heap:en, där man kan se hur minnesbehovet växlar och skräpsamlingen (GC). Det är också tydligt att underkanten sakta växer uppåt, vilket är en klar indikation på att allt minne inte återställs.
I mitten, visas antalet database connection open
respektive close
och jag har ringat in hur graferna divergerar. Med andra ord; något fler open
än close
. Underst, ser man antalet exceptions och de är många.
Efter det här kikade jag närmare i deras källkod och kunde för mig själv verifiera mina misstankar om hur man skrev sin databas-kod. JDBC är namnet på det API som används i Java för att interagera med en DB. Utmärkande för detta API är att man allokerar ett antal resursobjekt, som används och sen lämnas tillbaka.
Först allokerar man ett Connection
object, som används för att allokera ett Statement
objekt. När sedan en frågesats (query) körs allokeras ett ResultSet
objekt, som används för att iterera över svarsraderna. Man måste sen omsorgsfull återlämna dessa resursobjekt genom att anropa close
.
Om det uppstår ett exception i koden som arbetar med databasen finns risken att en eller fler anrop till close
bokstavligt talas hoppas över. Det var precis detta som inträffade i deras kod. Inte överallt, men då och då, vilket medförde att Connection
objekt förblev allokerade och inte i bruk.
Det här var långt innan Java utökades med try-closable satsen, vilken infördes i version 7 och förbättrades i version 9.
Min rekommendation var att skriva om JDBC koden med hjälp av JdbcTemplate
klassen från Spring Framework. Tillsammans gjorde vi en proof-of-concept och kunde sen verifiera att problemet var borta.
Jag har implementerat många Java applikationer med hjälp av Spring Framework, ända sedan jag första gången läste boken J2EE Design and Development av Rod Johnson, där han beskriver bean-factory, jdbc-template och vad som var de första stegen att forma det ramverk som skulle få namnet Spring.
Klassen JdbcTemplate har jag återkommit till många gånger, även när det funnits mer automagiska ramverk att tillgå, såsom Hibernate/JPA. Skälet är att jdbc-template har noll overhead och det är mycket enkelt att förstå exakt vad som kommer att exekveras.
I vår kurs om Spring Framework och Spring Boot visar jag bl.a. hur man använder jdbc-template direkt men också DB interaktion med JPA via Spring Boot. Ta en titt själv på vår kurs. Du hittar länken i slutet på denna artikel.
Under årens lopp har Spring figurerat på olika sätt i mina uppdrag, vilket jag får orsak till att återkomma med i någon senare artikel. Till sist, några bilder från området runt hotellet i Valencia, vilket kan kanske pigga upp nu när augusti tycks flyta bort med allt höstregn.