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.
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 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.
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:
...
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)
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)
** 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.
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