Danijel Mitar
Autor:
Danijel Mitar

Java developer

JVM – OutOfMemoryError

Što možemo učiniti kada aplikacija krajnjim korisnicima zadaje toliko problema da jedva mogu obavljati svoj posao? CPU i RAM na serveru su preopterećeni, procesi se ruše, operacije na bazi su spore i/ili je I/O wait na disku ogroman? Konkretno, ovaj blog post će se posvetiti problemu koji se može pojaviti unutar Java procesa – OutOfMemoryError.

Postoji više od šačice simptoma kada se borimo sa „podivljalim JVM-om“. Možemo imati OutOfMemoryError u log datotekama, CPU ili RAM su preopterećeni, kod ima memory leakove, problemi sa sinkronizacijom… Kada dođe do ovakve situacije – ne smijemo paničariti, trebamo se oboružati strpljenjem i pronaći način za riješiti uzrok, a ne simptome. U većini slučajeva rješavanje simptoma će imati nekakav izravan utjecaj, ali može zadati više problema nego što je riješilo.

Prva stvar koju trebamo napraviti je otvoriti log datoteku i potražiti iznimke, ukoliko pronađemo liniju:

java.lang.OutOfMemoryError: ...

onda naša aplikacija ima problema sa memorijom i pronalaženja pravog uzroka može biti vrlo izazovno.

Postoji više uzroka OutOfMemoryError-a unutar JVM-a:

  1.  Nema nativne memorije dostupne JVM-u
  2.  PermGen (do Jave 7) ili Metaspace (od Jave 8) prostor je ostao bez memorije
  3.  JVM troši previše vremena izvršavajući GC cikluse
  4.  Java heap je ostao bez memorije

Nema nativne memorije dostupne JVM-u

java.lang.OutOfMemoryError: unable to create new native thread

Uzrok ovog problema može biti alociranje heap memorije preblizu memorijskom limitu koji proces može koristiti (4GB u 32-bitnim sustavima, a u nekima i manje). Za primjer, recimo da je heap alociran na 3GB memorije, arhitektura je 32-bitna sa 4GB RAM-a i ostale aplikacije na serveru troše preostalu memoriju – više nema dostupne memorije za interne operacije JVM-a. Ako imamo sreće i ne treba nam heap od 3GB, alociranje manje heap memorije će riješit problem. U najgorem scenariju, kada ne možemo smanjiti heap i ne možemo utjecati na preostale aplikacije na serveru može se dogoditi da je nužno migrirati na 64-bitnu arhitekturu kako bi mogli koristiti više radne memorije (u današnje vrijeme je ovo manje vjerojatan scenarij jer je 64-bitna arhitektura postala standard).

PermGen/Metaspace je ostao bez memorije

java.lang.OutOfMemoryError: Metaspace/PermGen space

Jedan od uzroka ovog problema je memory leak u classloaderu. Vrlo vjerojatno ste se susreli sa ovim problemom prilikom hot deploya promjena u kodu na lokalni server (Tomcat ima ovaj problem). U tom slučaju, malo toga se može učiniti – pričekati da vendor riješi problem pa napraviti upgrade ili restartati server nakon svakog deploya. Također, ovaj problem se pojavljuje kada aplikacija koristi više klasa nego što ih stane u PermGen/Metaspace prostor. To je moguće ispraviti povećanjem PermGen/Metaspace prostora, ali ako pokušamo povećati PermGen/Metaspace prostor kada postoji memory leak u classloaderu – problem će samo biti odgođen. Heap histogrami mogu pomoći u otkrivanju pravog uzroka i mogu se dobiti upotrebom nekog od sljedećih alata komandne linije:

jcmd pid GC.class_histogram

jmap –histo pid

jmap –histo:live pid (live opcija će forsirati puni GC ciklus prije prikaza histograma)

JVM troši previše vremena izvršavajući GC cikluse

java.lang.OutOfMemoryError: GC overhead limit exceeded

je opis pogreške kada JVM troši previše vremena izvršavajući GC cikluse. Unutar JVM-a čak postoji i pravilo kada se navedena pogreška događa: pogreška je bačena nakon GC ciklusa, ako Java proces troši više od N% svog vremena izvršavajući GC (specificira se sa zastavicom: –XX:GCTimeLimit=N) i oslobođeni prostor je manji od N% veličine heapa (specificira se sa zastavicom: -XX:GCHeapFreeLimit=N) i takav način rada se ponavlja tijekom pet uzastopnih GC ciklusa i vrijednost zastavice –XX:UseGCOverheadLimit je true (što je i zadana vrijednost). Navedena pogreška može biti brzo otklonjena povećanjem heap memorije, ali najbolji način za otkrivanje pravog uzroka i pronalazak najboljeg mogućeg rješenja je analiza heap dumpa. Isto rješenje se primjenjuje i kada Java heap ostane bez memorije.

 Java heap je ostao bez memorije

java.lang.OutOfMemoryError: Java heap space

Dva su uzročnika problemu sa heap memorijom: aplikacija treba više heap memorije ili postoji memory leak unutar koda i to nije trivijalan problem. Povećanjem heap memorije ćemo na neki način dobiti trenutno poboljšanje performansi aplikacije, ali analiza heap dumpa bi trebala biti obavezna u svakom slučaju. U Javi postoje određene zastavice pomoću kojih je moguće dobiti heap dump:

  • -XX:+HeapDumpOnOutOfMemoryError – će kreirati heap dump datoteku prilikom OutOfMemoryError-a
  • -XX:HeapDumpPath<path> - putanja na kojoj će heap dump datoteka biti stvorena (.hprof je ekstenzija datoteke)
  • -XX:+HeapDumpAfterFullGC – će kreirati heap dump poslije punog GC ciklusa
  • -XX:+HeapDumpBeforeFullGC – će kreirati heap dump prije punog GC ciklusa

Uzimanje dva heap dumpa (prije i poslije GC ciklusa) može biti jako korisno: moguće je usporediti dvije datoteke i pomoću uočenih razlika otkriti pravi uzrok problema. Nužno je voditi računa da na disku imamo dovoljno prostora za heap dump – barem onoliko koliko je velika heap memorija. Osim prostora na disku, potrebno je i dovoljno radne memorije na računalu koje će analizirati heap dump. Teoretski, potrebno je barem onoliko RAM-a koliko je velik heap, a sa većom količinom RAM-a će proces analize biti brži. Nakon analize heap dumpa bi trebali imati dovoljno informacija o pravom stanju heapa – treba li alocirati više memorije ili postoji memory leak u aplikaciji.

Popularne teme
.NET ABAP ADFS Agile Always On Anemic Model Angular Azure Backbone BI BI projekti Bootstrap building people business inteligence Business Intelligence Change Chrome CI CITCON Claims compile Continuous Delivery continuous deployment Continuous Integration CSR d3js data data visualization Data visualization alati DDD dekompozicija dependency injection dinamička forma dinamički parametri dinamički query distribuirani razvoj Domain-Driven design DOP društvena odgovornost edge-based video analytics Eliminating waste enkapsulacija enterprise razvoj softvera ERP ETL Excel FIORI Frontend game Geopackage GPKG GIS Git Groovy heat map HICCUPS Hichert HTML IBCS interoperability invision IoT IPSO izvještavanje java java lambde benchmark JavaFX Javascript Jazz Build Engine JBE Jenkins jquery jqueryui jsfiddle JVM Kaizen Kanban KING ICT Kingovci Knockout kvaliteta leadership Lean M language Management Maven Metodologija microservices Microsoft mobile Mobility mockups moć monday game NetWeaver network nodejs OGC OKR open source optimizacija organizacija organizacijska struktura OutOfMemoryError outsourcing paginacija Performance performanse PERT PMI podatkovni skup pouzdanost Power BI Power Map Power Pivot Power Query Power View pretraga proces procjena Product Owner programming proizvod Project manager projektni plan radar Rational Team Concert razvoj tima Release resize responsive charts REST retrospektiva Rich-Domain model Roko Roić rolling wave planning RTC SAP scale scatterplot chart Scrum scrum team scrum tim service boundaries single responsibility principle Single Sign-On smart metering SoapUI social responsibility softver Software software prototyping Software Testing Club Spring Boot SQL standard sustav videonadzora svg Team team building team development Team Foundation Server terminski plan Testing tim timesheet timovi Toggl.com touch transakcijski nadzor tražilica Uspjeh Visual Studio vodstvo vodstvo leadership moć društvena odgovornost DOP social responsibility CSR vođenje projekata WBS Web Zagreb STC

PRIJAVA NA NEWSLETTER

Najnovije novosti iz ICT svijeta