Získání užitečných informací ze souborů logů je pro úspěch vaší aplikace v Javě klíčové. Data protokolů vám poskytnou cenné informace o výkonu, stabilitě a použitelnosti vaší aplikace.

Analýza dat protokolů se může zdát zdlouhavá, ale nemusí být. Existuje řada nástrojů pro čtení, analýzu a konsolidaci dat protokolu. Základní nástroje příkazového řádku, jako jsou grep, uniq a sort, mohou kombinovat a získávat užitečné informace ze souborů protokolu. Pokročilejší parsery protokolů, jako je Logstash nebo Fluentd, mohou z protokolů extrahovat klíčová data do snadno prohledávatelných tokenů. Cloudové služby pro ukládání protokolů, jako je SolarWinds® Loggly®, ukládají data protokolů za vás a nabízejí sofistikované možnosti analýzy, čímž eliminují potřebu udržovat protokoly sami.

Tato část se zabývá některými metodami a nástroji pro analýzu protokolů s cílem zlepšit vaše aplikace.

Zjištění nejčastějších výjimek

Zjištění nejčastějších výjimek vám může pomoci určit oblasti se špatným výkonem vaší aplikace Java. Většina logovacích rámců zaznamenává typ výjimky, zprávu o výjimce a metodu, ve které k výjimce došlo. Při použití Log4j bude protokol výjimek vypadat podobně jako jeden z následujících.

09:54:44.565 ERROR Log4jTest.MathClass - java.lang.ArithmeticException: / by zero10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: myFile (No such file or directory)10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: newFile (No such file or directory)

Pokud váš výstup obsahuje stopy zásobníku, podívejte se do části Rozbor víceřádkových stop zásobníku v této příručce.

Začněme jednoduchým příkladem s použitím populárního nástroje GNU grep. Poté si ukážeme, jak nám to může nástroj pro správu protokolů ještě více usnadnit.

Vyhledávání výjimek podle typu pomocí grepu

Následující unixový příkaz vyhledá výjimky, extrahuje typ výjimky a spočítá počet výskytů. grep je populární nástroj příkazového řádku, který provádí porovnávání vzorů, zatímco uniq a sort výsledky seskupí, resp. seřadí:

$ grep -o "\w*Exception" myLog.log | sort -r | uniq -c

V tomto příkladu regulární výraz \w*Exception odpovídá jakémukoli slovu, které končí na „výjimka“. Příznak -o říká grepu, aby vypsal pouze ty části výstupu, které odpovídají hledanému řetězci. Příznak sort -r seřadí výsledek v opačném pořadí, zatímco uniq -c seskupí výsledky a spočítá počet výskytů. Výsledkem je počet výjimek podle typu.

2 FileNotFoundException1 ArithmeticException

Pomocí grepu můžeme také vyhledat v protokolu každý konkrétní případ těchto výjimek.

$ grep ArithmeticException myLog.log09:54:44.565 ERROR Log4jTest.Log4jTest - java.lang.ArithmeticException: / by zero

Vrátí se každý řádek obsahující instanci hledaného řetězce ArithmeticException, přičemž samotný hledaný řetězec je ve výstupu zvýrazněn.

Vyhledávání výjimek podle třídy pomocí grepu

Vyhledávat výjimky můžete také podle třídy, ve které se vyskytly. Pro jednořádkové události protokolu následující příkaz seskupí počet výjimek podle třídy a typu. grep extrahuje název třídy tak, že hledá slovo následované určitým znakem (v tomto příkladu je použita pomlčka, i když lze použít jakýkoli znak, pokud je pro danou položku jedinečný). Tento znak sice není nezbytný, ale pomáhá nám vyhledat název třídy v události protokolu. Pomocí operátoru OR (označeného |) grep také extrahuje název výjimky vyhledáním slova obsahujícího řetězec „Exception“.

sed je další nástroj příkazového řádku, který lze použít k formátování výstupu z grepu. V tomto příkladu sed odstraní z našeho výstupu speciální znak a také všechny znaky nového řádku. Výstup je poté předán příkazům uniq a sort, které výsledky seskupí, respektive seřadí.

$ grep -o "w* -|\w*Exception" myLog.log | sed 'N; s/ -n/ /' | sort -r | uniq -c

Výsledek nás přibližuje ke klíčovým problémovým oblastem:

2 Log4jTest FileNotFoundException1 MathClass ArithmeticException

S těmito výsledky můžeme pomocí grepu zjistit další podrobnosti o problémech vyskytujících se v konkrétních třídách. Následující příkaz například vyhledá výjimky, které se vyskytly ve třídě MathClass.

$ grep -e "MathClass.*Exception" myLog.log09:54:44.565 ERROR Log4jtest.MathClass - java.lang.ArithmeticException: / by zero

Použití řešení pro správu protokolů

Většina řešení pro správu protokolů nabízí způsoby seskupování a vyhledávání záznamů protokolů na základě typu protokolu, obsahu zprávy, třídy, metody a vlákna. Pokud jsou již protokoly analyzovány a ukládány, mnoho řešení umí grafy a třídění výjimek podle počtu výskytů. V Loggly je to operace typu „ukaž a klikni“, takže se nemusíte učit nazpaměť složité příkazy grep. Loggly také indexuje záznamy protokolu, takže vyhledávání a počítání je mnohem rychlejší než grep. Pomocí průzkumníka polí můžeme například zobrazit seznam výjimek a jejich četnost a poté kliknutím na výjimku zobrazit všechny příslušné protokoly.

Pomocí průzkumníka polí Loggly rychle vyhledáme protokoly podle typu výjimky.

Loggly také nabízí nástroje pro vizualizaci, které mohou být informativnější než textový výstup z grepu. Grafy, jako je tento, vám mohou pomoci stanovit priority zdrojů pro vývojové sprinty nebo pro opravy po vydání nové verze.

Zobrazení výjimek podle četnosti v Loggly.

Odstraňování produkčních problémů

Pokud jde o produkční problémy, čas je nejdůležitější. Kritická chyba ve vaší aplikaci nejenže způsobí nespokojenost uživatelů, ale také sníží prodeje a důvěru ve vaši aplikaci nebo službu.

Ve většině případů lze řešení problému rozdělit do tří klíčových kroků:

  1. Shromáždění informací o problému
  2. Identifikace příčiny problému
  3. Nalezení řešení a zabránění opakování problému

Shromáždění informací o problému

Prvním krokem je shromáždění informací o problému. Shromážděte co nejvíce informací – snímky obrazovky, hlášení o pádu, protokoly, odkazy (u webových služeb) atd. a pomozte tak zúžit možné příčiny. Budete chtít, aby uživatel, u kterého se problém vyskytl, poskytl podrobné informace o události, včetně: kdy a kde v programu k problému došlo, jeho činnosti vedoucí k problému, operačního prostředí a jakéhokoli zvláštního nebo neobvyklého chování programu před a po výskytu problému.

Poté můžete začít shromažďovat informace z protokolů. Pokud je vaše aplikace hostovanou službou, začněte získávat protokoly z webových a aplikačních serverů. Pokud je vaše aplikace distribuovaným softwarovým balíkem, požádejte uživatele, aby do svého hlášení o chybě zahrnul data protokolu. Případně pokud vaše aplikace odesílá události protokolů na centralizovaný server protokolů, budou vaše protokoly okamžitě k dispozici.

Jakmile budete mít k dispozici přiměřené množství dat týkajících se problému, můžete jej začít sledovat v kódu.

Identifikace příčiny problému

Po shromáždění informací o problému je dalším krokem identifikace jeho příčiny. Reprodukce chyby ve vývojovém prostředí je jedním z nejjednodušších způsobů ověření její existence, ale může být časově náročná a nemusí fungovat ve všech případech. Pokud budete mít k dispozici důkladnou sadu protokolů, dostanete se přímo ke zdroji problému, což vám ušetří čas a frustraci.

Hlášení o chybě vám poskytne obecnou představu o tom, v čem problém spočívá a kde se vyskytl. Pomocí vybraného nástroje pro správu protokolů můžete zúžit vyhledávání na menší rozsah záznamů v protokolech vyhledáním jedinečného datového tokenu, jako je uživatelské jméno, ID relace nebo text zprávy.

Projděme si příkladový scénář, který ukáže, jak ladit systém. Představme si, že máme webové rozhraní pro vzdálené přihlášení k webové stránce. Webová stránka má přihlašovací obrazovku, která provádí základní ověření pomocí uživatelského jména a hesla. Uživatelé hlásí, že se nemohou k webové stránce přihlásit. Webová stránka přijme jejich vstup, ale poté selže s obecnou chybou.

Ukázka webové stránky hlásící chybu po pokusu o přihlášení.

Tato zpráva nám neposkytuje mnoho informací kromě obecného označení závažnosti protokolu. Vyhledávání záznamů s úrovní nebo zprávou „Severe“ ve správci protokolů může vést ke stovkám výsledků bez záruky, že některý z nich souvisí s daným problémem. Naštěstí náš Logger zaznamenal také uživatelské jméno uživatele, u kterého se chyba vyskytla, takže můžeme filtrovat podle uživatelského jména „admin“.

Pohled na výjimku Javy v Loggly.

Pokud se dostaneme hlouběji, zjistíme, že příčinou chyby je chybějící nebo neplatná tabulka. To je závažný problém, protože by to mohlo znamenat náhodné smazání nebo poškození databáze.

ERROR: Exception for user admincom.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test_schema.users' doesn't exist...com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651) at TestApplication.Test.doPost(Test.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at...

Pohledem do stack trace vidíme, že služba selhala na řádku 33 souboru Test.java. Tento řádek se skládá z příkazu SQL, který vytáhne data o uživateli z tabulky test_schema.users.

rs = stmt.executeQuery("SELECT * FROM test_schema.users WHERE username = " + username + " AND Password = " + password);

Pokud se pokusíme tento dotaz spustit v SQL frontendu, zjistíme, že tabulka „test_schema.users“ neexistuje. V databázi však existuje tabulka „test_schema.user“. V určitém okamžiku mohl vývojář omylem zadat špatný název tabulky a odeslat opravený formulář do výroby. Nyní víme, v čem je problém a kde se v našem kódu vyskytuje.

Pomocí aplikace SolarWinds Loggly můžete ladit a hledat hlavní příčinu problémů sledováním chyb v zásobníku aplikace, napříč více událostmi protokolu a dokonce i určením příslušného řádku kódu v systému GitHub.

Vyřešte problém a zabraňte jeho opakování

Teď, když jsme identifikovali problém a jeho příčinu, je posledním krokem jeho odstranění. Náš příklad přihlášení byl přehnaným případem s relativně snadným řešením, ale můžete narazit na složitější chyby, které mají kořeny v různých oblastech vaší aplikace. Než se vrhnete na rychlou a špinavou opravu, pečlivě zvažte, jaký dopad bude mít vaše změna na aplikaci. Je to skutečně nejlepší řešení problému? Je možné, že vaše změna bude kolidovat s jinou komponentou? Ztíží tato oprava zavedení nových oprav nebo funkcí v dalším vývoji? Zabrání tato oprava také tomu, aby se podobné problémy objevily později?“

Co když se například dvěma různým uživatelům podaří vytvořit dva různé účty se stejným uživatelským jménem a heslem? Mohli byste prosadit jedinečné uživatelské jméno pro všechny uživatele, ale jak by to ovlivnilo strukturu databáze, ověřovací kód a stávající základnu uživatelů? Mohli byste přidat nové jedinečné pole, například e-mailovou adresu, a zavést jeho povinné vyplnění, ale co když někteří ze stávajících uživatelů e-mailové adresy nedodali? Co když jsou některé e-mailové adresy sdílené mezi více účty? Jak tato nová pravidla ovlivní vaše registrační, vyhledávací a administrační stránky?“

Musíte také zvážit prodlevu mezi vytvořením opravy a jejím nasazením. V podnikovém prostředí bude muset být váš kód zkontrolován ostatními vývojáři, začleněn do kódové základny, sestaven, otestován QA, rozfázován a možná projde ještě několika dalšími kroky, než se dostane do produkce. Vaše společnost může mít specifické protokoly pro kritické nebo časově citlivé chyby, které musíte dodržovat. Jakmile naleznete řešení, uveďte své řešení v dokumentaci, stejně jako všechna rozumná řešení problému. Tímto způsobem mohou vaši zákazníci stále používat váš produkt a váš tým podpory může snížit počet duplicitních hlášení chyb, zatímco se oprava dostane do produkce.

Po nasazení opravy pokračujte v monitorování produkční aplikace, abyste ověřili, zda byl problém vyřešen. Například po nasazení opravy problému s databází ve výše uvedeném příkladu bychom již neměli vidět události s hlášením „Tabulka ‚test_schema.users‘ neexistuje“. Pokud chyby přetrvávají nebo se začnou zobrazovat nové chyby, víme, že oprava nefungovala. V ideálním případě uvidíme podobný vzorec jako na následujícím snímku obrazovky, kde počet chyb klesne na nulu ihned po nasazení opravy.

Kartogram počtu protokolů obsahujících chybu v aplikaci Loggly.

Další nástroje pro ladění produkčních aplikací

Ačkoli je protokolování osvědčenou metodou řešení problémů a ladění aplikací, tyto nástroje vám mohou pomoci získat větší přehled o fungování vaší aplikace.

jdb

jdb, Java Debugger, je nástroj příkazového řádku pro ladění tříd jazyka Java. jdb se snadno používá a je dodáván s vývojovou sadou Java Development Kit. Použití jdb vytvoří nový virtuální stroj Java (JVM), který umožňuje ladit třídu bez ovlivnění běžících programů. K ladění běžících aplikací můžete jdb použít také přidáním následujících parametrů do příkazu java:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n

Při spuštění JVM přiřadí číslo portu pro příchozí spojení jdb. Ke spuštěné instanci JVM se pak můžete připojit příkazem jdb -attach:

$ jdb -attach

Tímto způsobem můžete například připojit ladicí program ke spuštěné produkční instanci. V tomto případě buďte opatrní s použitím bodů přerušení, protože by mohlo dojít k pozastavení aktivního vlákna. To může mít následky, pokud například zákazník používá aplikaci v době, kdy ji ladíte. Další informace naleznete v dokumentaci jazyka Java k jdb.

OverOps

OverOps je sada nástrojů pro monitorování aplikací, analýzu kódu a odhalování problémů. Na rozdíl od softwaru pro protokolování, který se spoléhá na výstup generovaný běžící aplikací, se OverOps připojuje přímo k virtuálnímu stroji Java a mapuje kódovou základnu aplikace, čte proměnné a zaznamenává chyby. To mu umožňuje zachytit více chyb a zaznamenat více dat než dokonce i rámec pro protokolování aplikace. OverOps používá model software jako služba (SaaS), kdy se metriky shromažďují a ukládají na cloudových serverech OverOps. Můžete jej však nasadit i lokálně. V obou případech si můžete data prohlížet pomocí webového rozhraní.

BTrace

BTrace je trasovací nástroj, který umožňuje sledovat všechny aspekty aplikace, od názvů tříd až po chyby. BTrace používá aspektově orientovaný programovací přístup zahrnující použití anotací, které určují, kde a jak BTrace sleduje vaši aplikaci. Například následující skript BTrace sleduje a zaznamenává každé volání balíčku javax.swing.

import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*; @BTrace public class AllMethods { @OnMethod( clazz="/javax\.swing\..*/", method="/.*/" ) public static void m(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) { print(Strings.strcat("entered ", probeClass)); println(Strings.strcat(".", probeMethod)); }}

Další informace o BTrace najdete v repozitáři BTrace GitHub a ve Wiki.

Chronon

Chronon umožňuje přetáčet a přehrávat celý průběh provádění aplikace. Zaznamenává každou jednotlivou změnu provedenou během životnosti aplikace, což umožňuje reprodukovat stav aplikace v daném okamžiku. Záznamy se ukládají do souboru, což usnadňuje přenos historie provádění z produkčního stroje na vývojový stroj pro testování.

Chronon se skládá z nahrávacího serveru Chronon, který umožňuje vzdáleně nahrávat aplikace Java, vestavěného Chrononu, který vkládá nahrávač do aplikace, a ladicího programu Time Travelling Debugger, který umožňuje přehrávat záznamy.

jhsdb

jhsdb (Java HotSpot Debugger) je sada nástrojů pro ladění, analýzu a profilování výchozího JVM dodávaného s OpenJDK i Oracle JDK. jhsdb umožňuje připojit se ke spuštěným procesům Javy, pořizovat snímky stop zásobníku a dokonce analyzovat havarované JVM. Můžete jej použít k přístupu k haldě, vyrovnávací paměti kódu, statistikám garbage collection a dalším. Další informace najdete na stránce s dokumentací k jhsdb.

Sledování transakcí

Pokud dojde k problému, je důležité vědět, kde problém začal a jak ovlivnil zbytek aplikace. To je dost obtížné v monolitické aplikaci, ale ještě obtížnější je to v distribuované architektuře orientované na služby, kde jeden požadavek může zasáhnout desítky služeb. Ne vždy je zřejmé, která služba obsahuje hlavní příčinu chyby nebo jak ovlivnila ostatní služby. Sledování poskytuje údaje potřebné k tomu, abyste mohli sledovat cestu provádění aplikace a dopátrat se přesné příčiny problému.

V části příručky Ladění produkčních problémů jsme prošli příklad, kdy měl uživatel potíže s přihlášením do webové aplikace kvůli neplatné databázové tabulce. V této části si ukážeme, jak při řešení problému hrálo hlavní roli sledování transakcí.

Sledování jedinečných ID

Pro sledování posloupnosti událostí protokolu je třeba nějakým způsobem jednoznačně identifikovat související protokoly. Prostředí s více uživateli může generovat stovky stejných protokolů, což ztěžuje vyhledávání na základě časového razítka nebo Logger. Jednodušším řešením je připojit k souvisejícím záznamům protokolu jedinečný identifikátor. Tímto identifikátorem může být uživatelské jméno, ID relace, klíč API nebo univerzální jedinečný identifikátor (UUID). Naštěstí se pro tuto práci dokonale hodí ThreadContext.

V příkladu Ladění produkčních problémů jsme měli webové uživatelské rozhraní, které bylo umístěno v servletu Tomcat, který se připojoval k databázi MySQL. Uživatelé na webové stránce zadali své přihlašovací údaje a po stisknutí tlačítka odeslat servlet spustil dotaz porovnávající jejich přihlašovací údaje s údaji uloženými v databázi. Pokud byl uživatel úspěšně ověřen, byl přesměrován na hlavní stránku. Pokud došlo k chybě, byly zaznamenány podrobnosti o chybě a uživatelům byla zobrazena obecná zpráva.

Tento problém se nám podařilo odladit tak, že jsme do zprávy protokolu zahrnuli uživatelská jména uživatelů. To nám umožnilo rychle vyhledat události protokolu týkající se uživatele správce. V návaznosti na stejný příklad můžeme použít ThreadContext.put() k namapování uživatelského jména na Logger. Když uživatelé odešlou své přihlašovací údaje, servlet vstoupí do metody doPost(), která přidá uživatelská jména uživatelů do ThreadContext:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {ThreadContext.put("username", request.getParameter("username"));logger.info("Entering doPost().");...}

Při použití Log4j se vzorem %p : %m%n dostaneme následující záznam:

INFO : Entering doPost().

Podobné události můžeme přidat pro přístup k databázi MySQL, opuštění metody doPost a provádění dalších akcí. Pokud tedy uživatel vyvolá výjimku, víme přesně, co dělal, když k výjimce došlo.

Sledování volání metod

Mnoho logovacích frameworků poskytuje nativní metody pro sledování cesty provádění aplikace. Tyto metody se mezi jednotlivými frameworky mírně liší, ale mají stejný obecný formát.

  • traceEntry() označuje začátek metody.
  • traceExit() označuje konec metody. U metod, které vracejí objekt, můžete současně vrátit objekt a zaznamenat událost pomocí return logger.exit(object).
  • throwing() označuje výjimku, která pravděpodobně nebude zpracována, například RuntimeException.
  • catching() označuje výjimku, která nebude znovu zahozena.

Informace o těchto metodách specifické pro daný rámec najdete v dokumentaci Logger pro Log4j, Logback a java.util.logging.

Trasovací metody v Log4j

Na příkladu použití Log4j nahradíme metody Logger.info() v našem servletu trasovacími metodami.

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.entry(); ... logger.exit();}

Změníme také Appender's PatternLayout na zobrazení názvu třídy, metody a čísla řádku (konverzní vzory %class, %M a %line).

<PatternLayout pattern="%p %class %M %line: %m%n" />

Tracingové metody zaznamenávají události na úrovni TRACE, což znamená, že budeme muset změnit úroveň Logger's z DEBUG na TRACE. Jinak budou zprávy protokolu potlačeny.

<Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root></Loggers> TRACE DatabaseApplication.Login doPost 26: entry...TRACE DatabaseApplication.Login doPost 59: exit

Metody sledování také poskytují vlastní Markers. Například metody Logger.entry() a Logger.exit() zobrazují ENTER, respektive EXIT.

ENTER 14:47:41.074 TRACE DatabaseApplication.Login - EnterEXIT 14:47:41.251 TRACE DatabaseApplication.Login - Exit

Metody sledování v SLF4J

Uživatelé SLF4J mohou využít MDC ke sledování událostí protokolu. Podobně jako v Log4j lze hodnoty MDC použít s aplikátorem pomocí konverzního vzoru %X.

SLF4J také poskytuje metody entry(), exit(), throwing() a catching() prostřednictvím třídy XLogger (Extended Logger). Instanci XLogger můžete vytvořit pomocí XLoggerFactory.getXLogger().

package DatabaseApplication;import org.slf4j.Logger;import org.slf4j.LoggerFactory; import org.slf4j.ext.XLogger;import org.slf4j.ext.XLoggerFactory; public class Login extends HTTPServlet { final static XLogger xlogger = XLoggerFactory.getXLogger(Login.class.getName()); final static Logger logger = LoggerFactory.getLogger(Login.class.getName()); @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { xlogger.entry(); .. xlogger.exit(); }}

Přidejte do souboru logback.xml konverzní vzory %class a %line.

<configuration> <appender name="Console" class="ch.qos.Logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %class{36} %M %L: %msg%xEx%n</pattern> </encoder> </appender> <root level="trace"> ... </root></configuration>

Výsledné záznamy protokolu jsou totožné se záznamy vytvořenými pomocí Log4j.

Správa využití paměti

Správa paměti je ve vyšších jazycích, jako je Java, často opomíjena. Přestože průměrné množství paměti v moderních zařízeních roste, může mít vysoké využití paměti velký vliv na stabilitu a výkon aplikace. Jakmile virtuální stroj Java již nemůže alokovat paměť z operačního systému, může dojít k ukončení a pádu vašeho programu. Znalost správy paměti zabrání problémům při zvětšování velikosti vaší aplikace.

Představte si například, že bychom chtěli uložit sadu čísel počínaje jedničkou. Uživatel zadá horní hranici a program uloží každé celé číslo od „1“ do této hranice. K přidání každého čísla do pole použijeme cyklus while s čítačem.

import java.util.Scanner;...System.out.print("Please enter the maximum size of the array: ");Scanner scanner = new Scanner(System.in);int limit = scanner.nextInt(); ArrayList intArray = new ArrayList(); int count = 1;while (count <= limit) { intArray.add(count);}

Možná jste si všimli, že count se v cyklu nezvyšuje. To je velký problém; pokud uživatel zadá libovolné číslo větší než nula, pole bude růst tak dlouho, dokud JVM nevyužije veškerou dostupnou paměť a program nespadne.

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:2245)at java.util.Arrays.copyOf(Arrays.java:2219)at java.util.ArrayList.grow(ArrayList.java:242)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)at java.util.ArrayList.add(ArrayList.java:440)at MemoryTest.main(MemoryTest.java:10)

Garbage Collection

Pro snížení spotřeby paměti provádí virtuální stroj Java pravidelný proces čištění známý jako garbage collection. Garbage collection vyhledává bloky paměti, které se již nepoužívají, a zpřístupňuje je k opětovnému použití. Následující zdroje podrobněji vysvětlují proces garbage collection v jazyce Java.

  • Java Garbage Collection Basics (Oracle)
  • HotSpot Virtual Machine Garbage Collection Tuning Guide (Oracle)
  • Understanding G1 GC Logs (Poonam Bajaj)
  • Garbage Collection Tuning Guide (Atlassian)

Sběrač odpadu generuje diagnostické informace, které mohou být užitečné pro profilování výkonu aplikací. Tyto informace můžete zaznamenat tak, že při spuštění aplikace předáte JVM parametr -Xlog:gc. Po každém spuštění vypisuje garbage collector statistiky o procesu garbage collection ve formátu Unified JVM Logging. Zde je příklad:

 Using G1 Periodic GC disabled GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->1M(64M) 8.450ms

Using G1 říká, která metoda sběru odpadu se používá. Na víceprocesorových počítačích s velkým množstvím paměti RAM je často ve výchozím nastavení povolen sběrač odpadků Garbage-First (G1). Periodic GC disabled označuje, že proces sběru odpadků se nebude opakovat. Třetí řádek nám říká, že se jedná o evakuační pauzu, kdy jsou objekty kopírovány mezi oblastmi paměti podle toho, zda jsou stále používány. Pause Young nám říká, že proces vyčistil mladou generaci, kde jsou alokovány nové objekty. Výsledkem je, že celkové využití paměti objekty v mladé generaci kleslo ze 7M na 1M z 64M alokované paměti a proces zabral 8.450ms.

Když garbage collector vypisuje diagnostické informace do konzoly, můžeme vidět, jak množství alokované paměti (velikost haldy) v čase stále roste. Pro zjednodušení odstraníme časy procesoru.

$ java -Xlog:gc MemoryLeakDemo Using G1 Periodic GC disabled GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 25M->23M(64M) 4.372ms GC(1) Concurrent Cycle GC(1) Pause Remark 50M->34M(64M) 0.250ms GC(1) Pause Cleanup 94M->94M(124M) 0.057ms GC(1) Concurrent Cycle 169.695ms GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation) 94M->94M(124M) 3.738ms GC(3) Concurrent Cycle...

Kart zobrazující postupný nárůst využití haldy JVM v čase.

Ke každému záznamu můžete přidat časová razítka pomocí -XX:+PrintGCDateStamps a -XX:+PrintGCTimeStamps. Výstupy garbage collectoru můžete také zaznamenávat do souboru předáním-Xlog:gc:file: do JVM při spuštění aplikace.

Pokud sledujete soubory protokolů pomocí rsyslog, můžete pak protokoly předávat do centralizovaného systému protokolování, kde budou analyzovány a připraveny k analýze téměř v reálném čase. Zde je vidět, jak vypadá graf časové osy v aplikaci Loggly. Zobrazuje celkovou velikost haldy a také velikost haldy před a po spuštění garbage collectoru.

Úniky paměti

Únik paměti je situace, kdy program alokuje paměť rychleji, než ji může uvolnit. Únik paměti nejsnáze zjistíte, když program přestane reagovat, stane se nestabilním nebo způsobí OutOfMemoryErrors. V jazyce Java se s rostoucím využitím paměti objevuje více případů Full GCkolekcí.

Více informací o výstupu garbage collectoru a určení úniku paměti se dozvíte v kapitole Troubleshoot Memory Leaks v dokumentaci jazyka Java.

Další zdroje

Zkrácení času ladění bez napsání jediného řádku kódu (Loggly) – průvodce používáním Takipi

Konečný průvodce: 5 metod pro ladění produkčních serverů v měřítku (High Scalability)-Nástroje a techniky pro ladění produkčních problémů

Správa paměti

Průvodce laděním garbage collection (Oracle)-Průvodce pochopením a vyladěním garbage collection v Javě

Pochopení Java Garbage Collection (CUBRID Blog)-Průvodce garbage

Podívejte se. Analyzujte ji. Prohlédněte si ji. Vyřešte to

Podívejte se, na čem záleží.

START ZDARMA ZKUŠEBNÍ VERZE

.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.