Java-Kern: HotSpot-Compiler und C-Heap

Überblick

Für die vom HotSpot-Compiler durchgeführte native Codegenerierung und Optimierungsverarbeitung ist eine Syntaxanalyse des Zielcodes erforderlich. Der native Heap (C-Heap) wird als Speicherbereich für die Syntaxanalyse verwendet. Wenn eine große Methode oder eine komplizierte Syntax analysiert wird, wird auch der C-Heap entsprechend verwendet. In diesem Beitrag geht es darum zu sehen, wie der HotSpot-Compiler den C-Heap erhöht.

Java-Programme werden übrigens wie jede andere Sprache optimiert, jedoch nicht, wenn sie mit Javac kompiliert werden. Wenn es optimiert ist, wird das Java-Programm ausgeführt, und wenn der Code das Ziel der Kompilierung durch den HotSpot-Compiler ist, wird er durch den HotSpot-Compiler optimiert.

Lassen Sie uns ein einfaches Programm machen.

Um die Speichernutzung zu überprüfen, lassen Sie die Syntaxanalyse durchführen, bis der Compiler aufgibt, und überprüfen Sie vorher und nachher die Änderung der Speichernutzung. Der HotSpot-Compiler konnte keine gute Möglichkeit finden, Out Of Nodes aufzugeben, was zu endlos langem Code führte.

Das gesamte Programm finden Sie unter https://github.com/takimai39/sample/blob/master/OutOfNodes.java.

OutOfNodes.java


import java.io.*;
 
public class OutOfNodes {
    public static void main(String[] args) {
        for ( int n = 0 ; n < 2 ; n++ ) {
        // CompileThreshold=Da es 10000 ist, wird der HotSpot-Compiler nicht für die erste Schleife verwendet.
            System.out.println("Hit return to continue"); keyin();
            for ( int x = 0 ; x < 9999; x++) {
                challenge(); 
            }
        }
        System.out.println("Hit return to exit"); keyin();
    }

    private static void keyin() {
        BufferedReader userInputStreamReader = new BufferedReader(new InputStreamReader(System.in));
        try {
            String inputString = userInputStreamReader.readLine();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getX() {
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return(str);
    }

    private static String challenge() {

        String a[] = new String[300];
        String b[] = new String[300];

        a[0] = getX();
        a[1] = getX();
        // ...Ausgelassen, wiederholen Sie dieses Muster 230 Mal endlos... 
        b[0] = 0 + a[0];
        b[1] = 1 + a[1];
        // ...Wiederholen Sie 230 Mal auf die gleiche Weise...
        return(b[0]);
    }
}

Führen Sie das Programm aus und überprüfen Sie die Speichernutzung

Führen Sie es mit der Option PrintCompilation aus, um festzustellen, welche Methoden der HotSpot-Compiler kompiliert. Das Anzeigeformat ist von links Zeitstempel compilation_number Attribut Zeichen Klassenname :: Methodenname (Codegröße)

$ java -XX:+PrintCompilation OutOfNodes
Hit return to continue
   3106    1     n       java.lang.System::arraycopy (native)   (static)
   3108    2             java.lang.Integer::stringSize (21 bytes)
   3110    3             java.lang.Integer::getChars (131 bytes)
   3118    4             java.lang.Object::<init> (1 bytes)
   3118    5             java.lang.Math::min (11 bytes)
   3118    6             java.lang.AbstractStringBuilder::ensureCapacityInternal (16 bytes)
   3121    7             java.lang.String::length (6 bytes)
   3121    9             java.lang.AbstractStringBuilder::append (48 bytes)
   3124   10             java.lang.String::<init> (67 bytes)
   3125   11             java.util.Arrays::copyOfRange (63 bytes)
   3127   12             java.lang.StringBuilder::append (8 bytes)
   3129    8             java.lang.String::getChars (62 bytes)
   3130   13             java.lang.AbstractStringBuilder::<init> (12 bytes)
   3130   14             java.lang.StringBuilder::<init> (7 bytes)
   3130   15             java.lang.StringBuilder::toString (17 bytes)
   3130   16             OutOfNodes::getX (5 bytes)
   3130   17             java.lang.StringBuilder::append (8 bytes)
   3132   18             java.lang.AbstractStringBuilder::append (62 bytes)
Hit return to continue
 841500   19             OutOfNodes::challenge (7992 bytes)
 841658   20 %           OutOfNodes::main @ 20 (55 bytes)
Hit return to exit
 846756   19             OutOfNodes::challenge (7992 bytes)   COMPILE SKIPPED: out of nodes during split (not retryable)


Versuchen Sie auf einem anderen Terminalbildschirm, die Kerndatei abzurufen, während Sie die Prozessgröße beobachten. Nach Bestätigung von COMPILE SKIPPED: Wenn Sie die Größe erneut überprüfen, erhöht sie sich um ca. 64 MB.

$ pmap `jps | grep OutOfNodes | awk '{print $1}' ` | grep total
 total          2127304K

$ pmap `jps | grep OutOfNodes | awk '{print $1}' ` | grep total
 total          2192840K

Rufen Sie zur späteren Bestätigung mit dem Befehl gcore die Kerndatei für jede Situation ab.

Überprüfen Sie die Kerndatei mit gdb plus (CORE ANALYZER)

Sie können Befehle wie pmap ausgeben, aber es gibt CORE ANALYZER als Tool zum Überprüfen des von malloc () usw. zugewiesenen Speicherbereichs. Es ist ein großartiges Tool für alle, die die Kerndatei überprüfen. Befehle wie heap / v können mit gdb plus verwendet werden, das in diesem Kernanalysator enthalten ist. Darüber hinaus können Sie die Aufteilung jeder Arena mit heap / c überprüfen, um zu überprüfen, wie viele Bytes der Fläche aus dem Ausgabeergebnis zugeordnet sind.


$ /work/core_analyzer-master/bin/Linux/ptmalloc/gdb-7.11.1/gdb /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/bin/java ./core.24437.before

(gdb) heap /v Vor der Erhöhung der Speichernutzung
Warning: 17 mmap memory blocks were found while mp_ reports 16
Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_unwinders function is missing: 
        Tuning params & stats:
                mmap_threshold=131072
                pagesize=4096
                n_mmaps=16
                n_mmaps_max=65536
                total mmap regions created=16
                mmapped_mem=11202560
                sbrk_base=0x15b8000
        Main arena (0x7fb6ab64a760) owns regions:
                [0x15d900f - 0x15d9000] Total 17179869184.0GBFailed to get the first chunk at 0x15d8fff

        Dynamic arena (0x7fb670000020) owns regions:
                [0x7fb6700008c0 - 0x7fb670021000] Total 129KB in-use 1(312) free 3(129KB)
        Dynamic arena (0x7fb66c000020) owns regions:
                [0x7fb66c0008c0 - 0x7fb66c021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb678000020) owns regions:
                [0x7fb6780008c0 - 0x7fb678021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb674000020) owns regions:
                [0x7fb6740008c0 - 0x7fb674021000] Total 129KB in-use 11(3KB) free 1(126KB)
        Dynamic arena (0x7fb67c000020) owns regions:
                [0x7fb67c0008c0 - 0x7fb67c021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb68c000020) owns regions:
                [0x7fb68c0008c0 - 0x7fb68c021000] Total 129KB in-use 10(1KB) free 3(128KB)
        Dynamic arena (0x7fb688000020) owns regions:
                [0x7fb6880008c0 - 0x7fb688021000] Total 129KB in-use 3(22KB) free 2(107KB)
        Dynamic arena (0x7fb694000020) owns regions:
                [0x7fb6940008c0 - 0x7fb694021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb690000020) owns regions:
                [0x7fb6900008c0 - 0x7fb690021000] Total 129KB in-use 0(0) free 2(129KB)
        Dynamic arena (0x7fb698000020) owns regions:
                [0x7fb6980008c0 - 0x7fb698021000] Total 129KB in-use 0(0) free 2(129KB)
        Dynamic arena (0x7fb6a4000020) owns regions:
                [0x7fb6a40008c0 - 0x7fb6a40fe000] Total 1013KB in-use 1622(964KB) free 4(36KB)
        mmap-ed large memory blocks:

... 

Das Folgende ist der HotSpot-Compiler COMPILE SKIPPED: out of nodes...Es ist die Speichernutzung nach dem Werden.

(gdb) heap /v Nach erhöhter Speichernutzung
Warning: 18 mmap memory blocks were found while mp_ reports 16
Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_unwinders function is missing: 
        Tuning params & stats:
                mmap_threshold=8527872
                pagesize=4096
                n_mmaps=16
                n_mmaps_max=65536
                total mmap regions created=23
                mmapped_mem=11202560
                sbrk_base=0x15b8000
        Main arena (0x7fb6ab64a760) owns regions:
                [0x15d900f - 0x15d9000] Total 17179869184.0GBFailed to get the first chunk at 0x15d8fff

        Dynamic arena (0x7fb670000020) owns regions:
                [0x7fb6700008c0 - 0x7fb670021000] Total 129KB in-use 1(312) free 3(129KB)
        Dynamic arena (0x7fb66c000020) owns regions:
                [0x7fb66c0008c0 - 0x7fb66c021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb678000020) owns regions:
                [0x7fb6780008c0 - 0x7fb67807e000] Total 501KB in-use 14(6KB) free 4(494KB)
+       Dynamic arena (0x7fb674000020) owns regions: <--Diese Arena nimmt besonders zu!
+               [0x7fb664000030 - 0x7fb667b15000] Total 59MB in-use 4(127KB) free 4(58MB)
+               [0x7fb6740008c0 - 0x7fb678000000] Total 63MB in-use 49(51KB) free 12(63MB)
        Dynamic arena (0x7fb67c000020) owns regions:
                [0x7fb67c0008c0 - 0x7fb67c021000] Total 129KB in-use 1(312) free 2(129KB)
        Dynamic arena (0x7fb68c000020) owns regions:
                [0x7fb68c0008c0 - 0x7fb68c021000] Total 129KB in-use 10(1KB) free 3(128KB)
        Dynamic arena (0x7fb688000020) owns regions:
                [0x7fb6880008c0 - 0x7fb688021000] Total 129KB in-use 3(22KB) free 2(107KB)
        Dynamic arena (0x7fb694000020) owns regions:
                [0x7fb6940008c0 - 0x7fb694021000] Total 129KB in-use 4(560) free 1(129KB)
        Dynamic arena (0x7fb690000020) owns regions:
                [0x7fb6900008c0 - 0x7fb690021000] Total 129KB in-use 0(0) free 1(129KB)
        Dynamic arena (0x7fb698000020) owns regions:
                [0x7fb6980008c0 - 0x7fb698021000] Total 129KB in-use 10(6KB) free 2(122KB)
        Dynamic arena (0x7fb6a4000020) owns regions:
                [0x7fb6a40008c0 - 0x7fb6a40fe000] Total 1013KB in-use 1643(839KB) free 7(161KB)
        mmap-ed large memory blocks:

... 

Überprüfen Sie die Aufteilung der vergrößerten Arena

Sie können eine weitere Aufschlüsselung der Arena oben mit dem Befehl heap / c sehen. Der vergrößerte Bereich ist 56380088 Bytes frei, was fast frei und unbenutzt ist. Mit anderen Worten, der Bereich, der einst von malloc () verwendet wurde, aber nicht mehr benötigt und freigegeben wird, wird gezählt.

(gdb) heap /c 0x7fb664000030
        Dynamic arena (0x7fb674000020): [0x7fb664000020 - 0x7fb667b15000]
                [0x7fb664000030 - 0x7fb6675c4ae8] 56380088 bytes free
                        [0x7fb6675c4af0 - 0x7fb6675ccad8] 32744 bytes inuse
                [0x7fb6675ccae0 - 0x7fb6677ac8b8] 1965528 bytes free
                        [0x7fb6677ac8c0 - 0x7fb6677b48a8] 32744 bytes inuse
                [0x7fb6677b48b0 - 0x7fb667994868] 1966008 bytes free
                        [0x7fb667994870 - 0x7fb66799c858] 32744 bytes inuse
                        [0x7fb66799c860 - 0x7fb6679a4848] 32744 bytes inuse
                [0x7fb6679a4850 - 0x7fb667b15000] 1509296 bytes free

        Total inuse 4 blocks 130976 bytes
        Total free 4 blocks 61820920 bytes
(gdb)

Verwenden wir die Informationen zu empty_block als Hinweis.

Da es nur eine Kerndatei für Informationen gibt, ist es sehr schwierig zu bestimmen, wofür der freie () Bereich zuvor verwendet wurde. Wenn Sie jedoch noch an etwas denken, sind die Adressinformationen für empty_block in diesem Fall möglicherweise als Hinweis verfügbar. Der HotSpot-Compiler weist einen Speicherbereich zu, der in Einheiten namens Chunk verwendet werden soll, und legt die Adresse von empty_block fest, wenn die Verwendung beendet ist.

Auszug aus dem OpenJDK-Quellcode indexSet.cpp
...
    184 //---------------------------- IndexSet::free_block() -------------------------
    185 // Add a BitBlock to the free list.
    186 
    187 void IndexSet::free_block(uint i) {
    188   debug_only(check_watch("free block", i));
    189   assert(i < _max_blocks, "block index too large");
    190   BitBlock *block = _blocks[i];
    191   assert(block != &_empty_block, "cannot free the empty block");
    192   block->set_next((IndexSet::BitBlock*)Compile::current()->indexSet_free_block_list());
    193   Compile::current()->set_indexSet_free_block_list(block);
    194   set_block(i,&_empty_block);
    195 }

Überprüfen Sie die Adresse von empty_block mit gdb und sehen Sie, wie viel Sie in der Kerndatei finden können. Sie können sehen, dass sich im Kern viele leere Blockadressen befinden, nachdem COMPILE SKIPPED erstellt wurde.

(gdb) info var empty_block
All variables matching regular expression "empty_block":

File /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/indexSet.cpp:
IndexSet::BitBlock IndexSet::_empty_block;

Non-debugging symbols:
0x00007fb6ab053ac0  IndexSet::_empty_block
(gdb) 

$ od -An -x  -w8 core.24437.before | grep "7fb6 0000 3ac0 ab05" | wc -l
1
$ od -An -x  -w8 core.24437.after | grep "7fb6 0000 3ac0 ab05" | wc -l
54655
$

Wenn ich versuche, den Bereich um diesen Bereich herum zu entsorgen, ist das hässlich.

$ gdb /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/bin/java ./core.24437.after
...
(gdb) x/20gx 0x7fb665322f30
0x7fb665322f30: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f40: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f50: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f60: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f70: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f80: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322f90: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322fa0: 0x00007fb6756461c0      0x00007fb6ab053ac0
0x7fb665322fb0: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322fc0: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
(gdb) 
0x7fb665322fd0: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322fe0: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665322ff0: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323000: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323010: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323020: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323030: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323040: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323050: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
0x7fb665323060: 0x00007fb6ab053ac0      0x00007fb6ab053ac0
(gdb) 

Ich möchte ein wenig organisieren

** Was ist ein Knoten? ** **. Der Knoten in der Nachricht COMPILE SKIPPED: out of node während des Teilens ... ist ein Datenelement, nachdem es zur Kompilierungszeit durch Syntaxanalyse in eine Baumstruktur zerlegt wurde.

Müssen Sie Maßnahmen ergreifen?

Ich denke, es ist selten, dass die Speichernutzung von 64 MB zunimmt und die Kompilierungszeit von 5 Sekunden zu tatsächlichem Schaden führt. Da die Kompilierung immer fehlschlägt, geben Sie in der Datei .hotspot_compiler einen Ausschluss an, um zu verhindern, dass der HotSpot-Compiler darauf abzielt. Umgekehrt ist es möglich, MaxNodeLimit zu erhöhen und zu kompilieren, anstatt es auszuschließen. Wenn Sie das von Ihnen ausgeführte Java-Programm ändern können, können Sie den betreffenden Code noch weiter vereinfachen.

Ich denke, dass es nach gründlichen Tests eine Entscheidung sein wird, aber ich persönlich dachte, dass die Standardeinstellungen verwendet werden könnten, wenn es keinen tatsächlichen Schaden gäbe.

Recommended Posts

Java-Kern: HotSpot-Compiler und C-Heap
Java-Kern: HotSpot-Compiler stürzt unter SIGSEGV ab
C # und Java überschreiben Story
Java-Referenzmechanismus (Stack und Heap)
Mit Java verschlüsseln und mit C # entschlüsseln
Verknüpfen Sie Java- und C ++ - Code mit SWIG
Java Core: Sie können den Sicherheitspunkt nicht erreichen und hängen? !!
Die Richtung von Java in "C ++ Design and Evolution"
Von Java nach C und von C nach Java in Android Studio
Unterschiede beim Schreiben von Java-, C # - und Javascript-Klassen
Fassen Sie die Unterschiede zwischen C # - und Java-Schrift zusammen
Java und JavaScript
XXE und Java
Lösen mit Ruby, Perl und Java AtCoder ABC 128 C.
Organisieren Sie Builds in C ++ / Java- und Win / Linux-Kombinationen
Java-Sprache aus der Sicht von Kotlin und C #
Getter und Setter (Java)
[Java] Thread und ausführbar
Java wahr und falsch
[Java] Vergleich von Zeichenketten und && und ||
Java Core: gehackte Core-Datei
Brainfuck-> Java Byte Code Compiler
Java - Serialisierung und Deserialisierung
[Java] Argumente und Parameter
timedatectl und Java TimeZone
[Java] Verzweigen und Wiederholen
[Java] Variablen- und Typtypen
Java (Klasse und Instanz)
[Java] Überladen und überschreiben
Lösen mit Ruby, Perl und Java AtCoder ABC 113 C Referenz
Kotlin Post- und Pre-Inkrement und Operatorüberladung (Vergleich mit C, Java, C ++)
Lösen mit Ruby, Perl und Java AtCoder ABC 129 C (Teil 1)