Überprüfen Sie das Verhalten von Java Intrinsic Locks mit bpftrace

Überblick

Java verfügt über einen Mechanismus namens Intrinsic Locks. Jedes Objekt verfügt über eine eigene Sperre (Monitor-Sperre), und eine einfache Parallelverarbeitung mit mehreren Threads kann nur mit dem Schlüsselwort "synchronisiert" realisiert werden. Wie arbeiten die Threads zusammen, wenn das Programm ausgeführt wird? Verwenden Sie diesmal bpftrace, um dies zu überprüfen.

Arbeitsumgebung

OpenJDK 14

Die [Dtrace] -Funktion des JDK (https://docs.oracle.com/javase/8/docs/technotes/guides/vm/dtrace.html) ist erforderlich. Erstellen Sie sie daher aus dem Quellcode.

$ apt-get update
$ DEBIAN_FRONTEND=noninteractive ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && apt-get install -y tzdata && dpkg-reconfigure --frontend noninteractive tzdata
$ apt-get install build-essential autoconf systemtap-sdt-dev libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev libcups2-dev libfontconfig1-dev libasound2-dev unzip zip ccache -y

## clone source and boot jdk
$ mkdir jdk && cd jdk
$ git clone https://github.com/openjdk/jdk14u.git

$ wget https://download.java.net/java/GA/jdk13.0.2/d4173c853231432d94f001e99d882ca7/8/GPL/openjdk-13.0.2_linux-x64_bin.tar.gz
$ tar xvf openjdk-13.0.2_linux-x64_bin.tar.gz

$ cd jdk14u

$ bash configure --enable-debug --with-jvm-variants=server --enable-dtrace --with-boot-jdk=../jdk-13.0.2 --enable-ccache
$ make images

$ export JAVA_HOME=$PWD/build/linux-x86_64-server-fastdebug/jdk

bcc und bpftrace

## bcc
$ apt-get install -y linux-headers-$(uname -r) bison build-essential cmake flex g++ git libelf-dev zlib1g-dev libfl-dev systemtap-sdt-dev binutils-dev llvm-8-dev llvm-8-runtime libclang-8-dev clang-8 arping netperf iperf3 python3-distutils
$ git clone --recurse-submodules https://github.com/iovisor/bcc.git
$ mkdir bcc/build; cd bcc/build
$ cmake -DPYTHON_CMD=python3 ..
$ make -j8 && make install && ldconfig

$ cd ../..

## bpftrace

$ git clone https://github.com/iovisor/bpftrace.git
$ mkdir bpftrace/build; cd bpftrace/build

$ cmake -DHAVE_BCC_PROG_LOAD=ON -DHAVE_BCC_CREATE_MAP=ON -DBUILD_TESTING=OFF ..
$ make -j8 && make install

Bereiten Sie ein Beispielprogramm vor

Bereiten Sie jetzt dieses Java-Programm vor. Sie rufen lediglich zwei konkurrierende Bedrohungen auf.

Test.java


public class Test {

    private static synchronized void enter(String name) {
        try {
            System.out.println("enter " + name);
            Thread.sleep(1000);
            System.out.println("exit " + name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(() -> enter("foo"), "foo").start();
        new Thread(() -> enter("bar"), "bar").start();
    }
}

Kompilieren

$ $JAVA_HOME/bin/javac Test.java

Ausführung und Ergebnisse

Starten Sie zuerst diesen Befehl bpftrace in einem anderen Terminal, um die Ablaufverfolgung vorzubereiten.

$ bpftrace - <<EOF
BEGIN { printf("%-12s %-6s %-27s %s\n", "TIME", "TID", "ACTION", "DESC"); }

usdt:$JAVA_HOME/lib/server/libjvm.so:hotspot:thread__start { printf("%-12ld %-6d %-27s", elapsed, arg2, "start");printf("name=%s\n", str(arg0)); }
usdt:$JAVA_HOME/lib/server/libjvm.so:hotspot:thread__stop { printf("%-12ld %-6d %-27s", elapsed, arg2, "stop");printf("name=%s\n", str(arg0)); }

usdt:$JAVA_HOME/lib/server/libjvm.so:hotspot:monitor__contended__enter { printf("%-12ld %-6d %-27s", elapsed, arg0, "monitor_contended_enter"); printf("monitor=0x%lx, class=%s\n", arg1, str(arg2)); }
usdt:$JAVA_HOME/lib/server/libjvm.so:hotspot:monitor__contended__entered { printf("%-12ld %-6d %-27s", elapsed, arg0, "monitor_contended_entered"); printf("monitor=0x%lx, class=%s\n", arg1, str(arg2)); }
usdt:$JAVA_HOME/lib/server/libjvm.so:hotspot:monitor__contended__exit { printf("%-12ld %-6d %-27s", elapsed, arg0, "monitor_contended_exit"); printf("monitor=0x%lx, class=%s\n", arg1, str(arg2)); }
EOF

Attaching 6 probes...

Führen Sie als Nächstes das vorherige Java-Programm aus

$ $JAVA_HOME/bin/java -XX:+ExtendedDTraceProbes  Test
enter bar
exit bar
enter foo
exit foo

Die beiden Bedrohungen liefen nacheinander. Was ist also mit der Rückverfolgung?

Attaching 6 probes...
TIME         TID    ACTION                      DESC
3568183750   2      start                      name=Reference Handler
3568644123   3      start                      name=Finalizer
3581708591   1      monitor_contended_exit     monitor=0x7f7314003100, class=java/lang/Object����
3583984755   4      start                      name=Signal Dispatcher
3584404128   6      start                      name=C2 CompilerThread0
3584475441   5      start                      name=Service Thread
3584812927   7      start                      name=C1 CompilerThread0
3585382491   8      start                      name=Sweeper thread
3618900047   9      start                      name=Common-Cleaner
4170272484   2      monitor_contended_exit     monitor=0x7f7314005100, class=java/lang/ref/ReferenceQueue$Lock���#
4176664886   10     start                      name=Notification Thread
4201863620   11     start                      name=foo
4202328663   12     start                      name=bar
4203255448   11     monitor_contended_enter    monitor=0x7f7314007000, class=java/lang/Class�����
5229989467   12     monitor_contended_exit     monitor=0x7f7314007000, class=java/lang/Class�����
5230226530   11     monitor_contended_entered  monitor=0x7f7314007000, class=java/lang/Class�����
5230593438   12     stop                       name=bar
6242293321   11     stop                       name=foo
6247012424   4      stop                       name=Signal Dispatcher

Was Sie hier sehen können, ist, dass nach dem Start einer Reihe von JVM-Systembedrohungen auch die Bedrohungen "foo" und "bar" gestartet wurden. Und foo befindet sich jetzt im Zustand monitor_contended_enter, da natürlich der bar zuerst in den kritischen Bereich eingetreten ist. Danach wird "bar" zu "monitor_contended_exit" und verlässt den kritischen Bereich. Sofort wurde "foo" auch zu "monitor_contended_entered" und die Ausführung begann.

Zusammenfassung

Es ist eine einfache Anwendung, aber bpftrace oder bcc ist ein sehr leistungsfähiges Werkzeug, und ich möchte in Zukunft weitere Möglichkeiten ausloten.

Referenzmaterial

Recommended Posts

Überprüfen Sie das Verhalten von Java Intrinsic Locks mit bpftrace
Überprüfen Sie den Inhalt des Java-Zertifikatspeichers
Überprüfen Sie den Inhalt der Parameter mit pry
Anmerkung: [Java] Überprüfen Sie den Inhalt des Verzeichnisses
[Java] Überprüfen Sie die Anzahl der Zeichen
[Java] [Spring] Testen Sie das Verhalten des Loggers
Überprüfen Sie den MX-Eintrag der E-Mail-Adresse mit Java und die Domain
Berechnen Sie die Ähnlichkeitsbewertung von Zeichenketten mit JAVA
Zusammenfassung des ToString-Verhaltens mit Java- und Groovy-Annotationen
[Java] Überprüfen Sie die JDK-Version der erstellten Kriegsdatei
Überwachen Sie den internen Status von Java-Programmen mit Kubernetes
Überprüfen Sie das Ergebnis der generischen Parameterinferenz mit JShell
Überprüfen Sie das Verhalten von include, exclude und ExhaustedRetryException von Spring Retry
Die Geschichte von dto, dao-like mit Java, SQLite
Ersetzen Sie nur einen Teil des URL-Hosts durch Java
Ich habe das Verhalten von Java Scanner und .nextLine () nicht wirklich verstanden.
Befehl zum Überprüfen der Anzahl und des Status von Java-Threads
Überprüfen Sie die Funktion von zwei Rollen mit einer Chat-Anwendung
Überprüfen Sie den Status der Java-Anwendung, ohne das Überwachungstool zu verwenden
Java-Anfänger fassten das Verhalten von Array und ArrayList kurz zusammen
[Java] Vereinfachen Sie die Implementierung der Datenverlaufsverwaltung mit Reladomo
[Java] Überprüfen Sie den Unterschied zwischen orElse und orElseGet mit IntStream
Informationen zum Verhalten beim Erstellen einer Dateizuordnung mit Java
Stellen Sie sicher, dass Sie das Java compareTo-Ergebnis mit 0 vergleichen
Über das Verhalten von Ruby Hash # ==
[Java 8] Doppelte Löschung (& doppelte Überprüfung) mit Stream
[Java] Löschen Sie die Elemente von List
[Schienen] Überprüfen Sie den Inhalt des Objekts
[Java1.8 +] Mit LocalDate das Datum des nächsten × Tages abrufen
[Java Edition] Geschichte der Serialisierung
Überprüfen Sie die Version von Cent OS
Die Geschichte, das Verhalten von String durch Passieren von Java nicht zu kennen
Probieren Sie HelloWorld mit der Mindestkonfiguration von Heroku Java Spring-Boot aus
[Java] Elementexistenzprüfung mit Stream
Überprüfen Sie den Migrationsstatus von Schienen
Folgen Sie dem Link mit Selen (Java)
Eine Geschichte über das Erreichen der League Of Legends-API mit JAVA
Ich habe versucht, den Betrieb des gRPC-Servers mit grpcurl zu überprüfen
Der Suchtpunkt bei der Durchführung der Basisauthentifizierung mit Java URLConnection
Sehen Sie sich das Verhalten von Entitätsaktualisierungen mit Spring Boot + Spring Data JPA an
Überschreiben Sie den gleichnamigen Upload mit dem BOX SDK (Java).
So überprüfen Sie den Inhalt der Java-Zeichenfolge mit fester Länge
Stellen Sie die Sensorinformationen von Raspberry Pi in Java grafisch dar und überprüfen Sie sie mit einem Webbrowser
Das Verhalten von JS auf Java SE 8 Nashorn änderte sich plötzlich
Ist die von Ihnen verwendete Version von Elasticsearch mit Java 11 kompatibel?
Der Ursprung von Java-Lambda-Ausdrücken
Die Geschichte eines Game Launcher mit automatischer Ladefunktion [Java]
Lassen Sie uns das Ergebnis der Analyse von Java-Bytecode in einem Klassendiagramm ausdrücken
[Java] Überprüfen Sie, ob die Zeichenfolge nur aus Leerzeichen besteht (= Leerzeichen)
[Java] Holen Sie sich MimeType aus dem Inhalt der Datei mit Apathce Tika [Kotlin]
Überprüfen Sie den Betrieb mit dem Steg mit Maven.
Holen Sie sich das Ergebnis von POST in Java
Untersuchen Sie die Speichernutzung von Java-Elementen
[Java] Ermittelt den Tag eines bestimmten Tages
Vergleichen Sie Elemente eines Arrays (Java)
[Tag: 5] Ich habe die Grundlagen von Java zusammengefasst
Was sind die aktualisierten Funktionen von Java 13
Messen Sie einfach die Größe von Java-Objekten
Rückblick auf die Grundlagen von Java
Überprüfen Sie den Verarbeitungsinhalt mit [Rails] Binding.pry
Ausgabe des Buches "Einführung in Java"