Java >> Java tutorial >  >> JVM

Liste over alle klasser, der er indlæst i JVM

1. Oversigt

I denne øvelse lærer vi forskellige teknikker til at liste alle klasser indlæst i JVM. For eksempel kan vi indlæse JVM's heap-dump eller forbinde de kørende applikationer til forskellige værktøjer og liste alle de klasser, der er indlæst i det værktøj. Der er også forskellige biblioteker til at opnå dette programmæssigt.

Vi vil undersøge både de ikke-programmatiske og programmatiske tilgange.

2. Ikke-programmatisk tilgang

2.1. Brug af VM-argument

Den mest ligetil tilgang til at liste alle indlæste klasser ville være at logge det i en konsoludgang eller fil.

Vi kører Java-applikationen med nedenstående JVM-argument:

java <app_name> --verbose:class
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Object from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.io.Serializable from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.Comparable from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.CharSequence from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.String from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.reflect.AnnotatedElement from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.reflect.GenericDeclaration from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.reflect.Type from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
[Loaded java.lang.Class from /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar] 
...............................

Til Java 9 bruger vi -Xlog JVM-argument for at logge de klasser, der er indlæst i filen:

java <app_name> -Xlog:class+load=info:classloaded.txt

2.2. Brug af Heap Dump

Vi vil se, hvordan forskellige værktøjer bruger JVM-heap-dumpen til at udtrække klasseindlæst information. Men først genererer vi heap-dumpet ved hjælp af kommandoen nedenfor:

jmap -dump:format=b,file=/opt/tmp/heapdump.bin <app_pid>

Ovenstående heap-dump kan åbnes i forskellige værktøjer for at få forskellige metrics.

I Eclipse indlæser vi heap-dump-filen heapdump.bin i Eclipse Memory Analyzer og brug Histogram Interface:

Vi åbner nu heap-dump-filen heapdump.bin i Java VisualVM-grænsefladen og brug klasserne efter instanser eller størrelsesindstilling:

2.3. JProfiler

JProfiler er en af ​​de bedste Java Application Profilers med et rigt sæt funktioner til at se forskellige metrics.

I JProfiler kan vi vedhæfte til kørende JVM eller indlæse heap-dump-filen og få alle de JVM-relaterede metrics, inklusive navne på alle indlæste klasser.

Vi bruger funktionen vedhæft proces til at lade JProfiler oprette forbindelse til den kørende applikation ListLoadedClass :

Derefter tager vi et øjebliksbillede af applikationen og bruger det til at få alle klasser indlæst:

Nedenfor kan vi se navnene på de indlæste klasseforekomster ved hjælp af Heap Walker-funktionalitet:

3. Programmatisk tilgang

3.1. Instrumentation API

Java leverer Instrumentation API, som hjælper med at få værdifulde metrics på applikationen. Først skal vi oprette og indlæse en Java Agent for at erhverve en forekomst af Instrumentation grænseflade til applikationen. En Java-agent er et værktøj til at instrumentere programmer, der kører på JVM.

Derefter bliver vi nødt til at påberåbe Instrumentation metode getInitiatedClasses(Classloader loader) for at få alle klasserne indlæst af en bestemt klasseindlæsertype.

3.2. Google Guava

Vi vil se, hvordan Guava-biblioteket kan få en liste over alle klasser indlæst i JVM ved hjælp af en aktuel klasseindlæser.

Lad os starte med at tilføje Guava-afhængigheden til vores Maven-projekt:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

Vi initialiserer Klassestien objekt med den aktuelle klasseindlæserinstans:

ClassPath classPath = ClassPath.from(ListLoadedClass.class.getClassLoader());
Set<ClassInfo> classes = classPath.getAllClasses();
Assertions.assertTrue(4 < classes.size());

3.3. Reflections API

Vi bruger Reflections-biblioteket, der scanner den aktuelle klassesti og giver os mulighed for at forespørge på den under kørsel.

Lad os starte med at tilføje reflekserne afhængighed af vores Maven-projekt:

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.10.2</version>
</dependency>

Nu vil vi se på eksempelkoden, som returnerer et sæt klasser under en pakke:

Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
Set<Class> classes = reflections.getSubTypesOf(Object.class)
  .stream()
  .collect(Collectors.toSet());
Assertions.assertEquals(4, classes.size());

4. Konklusion

I denne artikel har vi lært forskellige måder at liste alle klasser indlæst i JVM. For det første har vi set, hvordan brug af et VM-argument kan logge listen over indlæste klasser.

Derefter har vi undersøgt, hvordan forskellige værktøjer kan indlæse heap-dumpen eller oprette forbindelse til JVM'et for at vise forskellige metrics, herunder indlæste klasser. Til sidst har vi dækket nogle af Java-bibliotekerne.

Som altid er al koden tilgængelig på GitHub.


No
Java tag