Heim  >  Artikel  >  Java  >  Warum benötigt JVM eine Leistungsoptimierung?

Warum benötigt JVM eine Leistungsoptimierung?

青灯夜游
青灯夜游Original
2020-04-21 15:21:194407Durchsuche

Warum benötigt JVM eine Leistungsoptimierung?

Ziel der JVM-Optimierung: Verwenden Sie einen kleineren Speicherbedarf, um einen höheren Durchsatz oder eine geringere Latenz zu erzielen.

Manchmal kommt es beim Testen oder Ausführen des Programms vor dem Online-Gehen zu großen und kleinen JVM-Problemen, wie z. B. übermäßige CPU-Last, Anforderungsverzögerung, reduzierte TPS usw. und sogar Speicherlecks (verwendet). (für jede Garbage Collection) Die Zeit wird immer länger, die Häufigkeit der Garbage Collection wird immer höher und die von jeder Garbage Collection bereinigten Mülldaten werden immer kleiner.) Ein Speicherüberlauf führt zum Absturz des Systems Die JVM muss so optimiert werden, dass das Programm normal ausgeführt werden kann, um eine höhere Benutzererfahrung und Betriebseffizienz zu erreichen.

Hier sind einige wichtige Indikatoren:

  • Speichernutzung: die Menge an Speicher, die für den normalen Betrieb des Programms erforderlich ist.

  • Latenz: Programmpausenzeit aufgrund der Speicherbereinigung.

  • Durchsatz: Das Verhältnis der Laufzeit des Benutzerprogramms zur Gesamtzeit, die das Benutzerprogramm und die Speicherbereinigung in Anspruch nehmen.

Natürlich ist es genau wie beim CAP-Prinzip unmöglich, gleichzeitig den geringen Speicherbedarf, die geringe Latenz und den hohen Durchsatz eines Programms zu erfüllen. Die Ziele des Programms sind unterschiedlich , und die Richtung, die beim Tuning berücksichtigt werden muss Es ist auch anders. Vor dem Tuning müssen Sie das tatsächliche Szenario kombinieren, klare Optimierungsziele haben, den Leistungsengpass finden, den Engpass gezielt optimieren und schließlich Tests durchführen, um zu bestätigen, ob Die Tuning-Ergebnisse erfüllen die Anforderungen durch verschiedene Überwachungstools.

JVM-Tuning-Tool

(1) Zu den Daten, auf die sich das Tuning verlassen und auf die es sich beziehen kann, gehören Systemlaufprotokolle, Stack-Fehlermeldungen, GC-Protokolle, Thread-Snapshots usw Heap-Transfers, Speichern von Snapshots usw.

① Systembetriebsprotokoll: Das Systembetriebsprotokoll ist das im Programmcode gedruckte Protokoll, das den Systembetriebsverlauf auf Codeebene beschreibt (Ausführungsmethode, Eingabeparameter, Rückgabewert usw.). Wenn ein Problem mit dem System vorliegt, ist das Systembetriebsprotokoll das erste zu überprüfende Protokoll.

② Stack-Fehlerinformationen: Wenn im System eine Ausnahme auftritt, kann das Problem zunächst anhand der Stack-Informationen lokalisiert werden. Beispielsweise anhand von „java.lang.OutOfMemoryError: Java-Heap-Speicherplatz“. basierend auf „java. „lang.StackOverflowError“ kann als Stapelüberlauf beurteilt werden; „java.lang.OutOfMemoryError: PermGen space“ kann als Methodenbereichsüberlauf usw. beurteilt werden .

③GC-Protokoll: Verwenden Sie -XX:+PrintGCDetails und -Xloggc:/data/jvm/gc.log, wenn das Programm startet, um den detaillierten Prozess von gc aufzuzeichnen, während das Programm ausgeführt wird, oder konfigurieren Sie „-verbose“ direkt Der Parameter „: gc“ gibt das GC-Protokoll an die Konsole aus. Mithilfe des aufgezeichneten GC-Protokolls können Häufigkeit, Zeit usw. von GC in jedem Speicherbereich analysiert werden, um Probleme zu finden und eine gezielte Optimierung durchzuführen.

Zum Beispiel das folgende GC-Protokoll:

2018-08-02T14:39:11.560-0800: 10.171: [GC [PSYoungGen: 30128K->4091K(30208K)] 51092K->50790K(98816K), 0.0140970 secs] [Times: user=0.02 sys=0.03, real=0.01 secs]
2018-08-02T14:39:11.574-0800: 10.185: [Full GC [PSYoungGen: 4091K->0K(30208K)] [ParOldGen: 46698K->50669K(68608K)] 50790K->50669K(98816K) [PSPermGen: 2635K->2634K(21504K)], 0.0160030 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
2018-08-02T14:39:14.045-0800: 12.656: [GC [PSYoungGen: 14097K->4064K(30208K)] 64766K->64536K(98816K), 0.0117690 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]
2018-08-02T14:39:14.057-0800: 12.668: [Full GC [PSYoungGen: 4064K->0K(30208K)] [ParOldGen: 60471K->401K(68608K)] 64536K->401K(98816K) [PSPermGen: 2634K->2634K(21504K)], 0.0102020 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

Es gibt insgesamt 4 GC-Protokolle, wenn man sich die erste Zeile des Protokolls ansieht: „2018-08-02T14:39:11.560-0800“. ist ein genaues UTC-Standardzeitformat auf Millisekundenebene. Durch Konfigurieren des Parameters „-XX:+PrintGCDateStamps“ kann dieser Zeitstempel nach dem GC-Protokoll ausgedruckt werden. „10.171“ ist die Anzahl der Sekunden, die vom Start der JVM bis zum Auftreten von GC. Das „[GC“ am Anfang der ersten Zeile des Protokolltexts zeigt an, dass Stop-The-World in diesem GC nicht aufgetreten ist (der Benutzerthread wurde angehalten). Das „[Full GC“ am Anfang der zweiten Zeile des Protokolls Der Text weist darauf hin, dass Stop-The-World in dieser GC-Welt aufgetreten ist, daher haben [GC und [Full GC] nichts mit der neuen Generation und der alten Generation zu tun, sondern hängen mit der Art des Garbage Collectors zusammen, wenn Sie System aufrufen .gc() direkt, [Vollständiger GC(System) wird angezeigt. Die nächsten „[PSYoungGen““ und „[ParOldGen““ stellen den Bereich dar, in dem GC auftritt. Der angezeigte spezifische Name bezieht sich beispielsweise auf den „Parallel Scavenge Collector“. Der Serial Old-Sammler zeigt außerdem „[DefNew““ an, der ParNew-Kollektor zeigt „[ParNew““ usw. an. Das folgende „30128K->4091K (30208K)“ zeigt an, dass nach diesem gc der Speichernutzungsraum in diesem Bereich von 30128K auf 4091K reduziert wurde und die Gesamtspeichergröße 30208K beträgt. „51092K->50790K(98816K), 0,0140970 Sekunden“ nach der GC-Beschreibung jedes Bereichs. Nach dieser Speicherbereinigung wurde der Speichernutzungsraum des gesamten Heap-Speichers von 51092K auf 50790K reduziert und der Gesamtspeicherplatz des gesamten Heap-Speichers war 98816K. GC dauerte 0,0140970 Sekunden.

④Thread-Snapshot: Wie der Name schon sagt, können Sie den Status des Threads zu einem bestimmten Zeitpunkt anhand des Thread-Snapshots sehen, wenn im System ein Anforderungszeitlimit, eine Endlosschleife, ein Deadlock usw. vorliegt. Sie können dies anhand der Thread-Snapshot-Frage weiter bestimmen. Durch Ausführen des mit der virtuellen Maschine gelieferten Befehls „jstack pid“ können Sie die Snapshot-Informationen der Threads im aktuellen Prozess sichern. Es gibt viele Beispiele im Internet für eine detailliertere Verwendung und Analyse. Dieser Artikel ist bereits sehr lang. Deshalb werde ich nicht auf Details eingehen. Veröffentlichen Sie einen Blog als Referenz: http://www.cnblogs.com/kongzhongqijing/articles/3630264.html

⑤Heap-Dump-Snapshot: Sie können „-XX“ verwenden: +HeapDumpOnOutOfMemory“ und „-XX:HeapDumpPath=/data/jvm/dumpfile.hprof“, wenn im Programm ein Speicherüberlauf auftritt, wird der Speicher-Snapshot zu diesem Zeitpunkt in Form einer Datei ausgegeben (Sie können dies auch direkt verwenden jmap-Befehl, um den Speicher jederzeit zu sichern, wenn das Programm ausgeführt wird (Snapshot) und anschließend die Speichernutzung zu diesem Zeitpunkt zu analysieren.

(2) JVM-Tuning-Tool

①用 jps(JVM process Status)可以查看虚拟机启动的所有进程、执行主类的全名、JVM启动参数,比如当执行了JPSTest类中的main方法后(main方法持续执行),执行 jps -l可看到下面的JPSTest类的pid为31354,加上-v参数还可以看到JVM启动参数。

3265 
32914 sun.tools.jps.Jps
31353 org.jetbrains.jps.cmdline.Launcher
31354 com.danny.test.code.jvm.JPSTest
380

 ②用jstat(JVM Statistics Monitoring Tool)监视虚拟机信息 
jstat -gc pid 500 10 :每500毫秒打印一次Java堆状况(各个区的容量、使用容量、gc时间等信息),打印10次

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
11264.0 11264.0 11202.7  0.0   11776.0   1154.3   68608.0    36238.7     -      -      -      -        14    0.077   7      0.049    0.126
11264.0 11264.0 11202.7  0.0   11776.0   4037.0   68608.0    36238.7     -      -      -      -        14    0.077   7      0.049    0.126
11264.0 11264.0 11202.7  0.0   11776.0   6604.5   68608.0    36238.7     -      -      -      -        14    0.077   7      0.049    0.126
11264.0 11264.0 11202.7  0.0   11776.0   9487.2   68608.0    36238.7     -      -      -      -        14    0.077   7      0.049    0.126
11264.0 11264.0  0.0    0.0   11776.0   258.1    68608.0    58983.4     -      -      -      -        15    0.082   8      0.059    0.141
11264.0 11264.0  0.0    0.0   11776.0   3076.8   68608.0    58983.4     -      -      -      -        15    0.082   8      0.059    0.141
11264.0 11264.0  0.0    0.0   11776.0    0.0     68608.0     390.0      -      -      -      -        16    0.084   9      0.066    0.149
11264.0 11264.0  0.0    0.0   11776.0    0.0     68608.0     390.0      -      -      -      -        16    0.084   9      0.066    0.149
11264.0 11264.0  0.0    0.0   11776.0   258.1    68608.0     390.0      -      -      -      -        16    0.084   9      0.066    0.149
11264.0 11264.0  0.0    0.0   11776.0   3012.8   68608.0     390.0      -      -      -      -        16    0.084   9      0.066    0.149

jstat还可以以其他角度监视各区内存大小、监视类装载信息等,具体可以google jstat的详细用法。

③用jmap(Memory Map for Java)查看堆内存信息 
执行jmap -histo pid可以打印出当前堆中所有每个类的实例数量和内存占用,如下,class name是每个类的类名([B是byte类型,[C是char类型,[I是int类型),bytes是这个类的所有示例占用内存大小,instances是这个类的实例数量:

num     #instances         #bytes  class name
----------------------------------------------
  1:          2291       29274080  [B
  2:         15252        1961040  <methodKlass>
  3:         15252        1871400  <constMethodKlass>
  4:         18038         721520  java.util.TreeMap$Entry
  5:          6182         530088  [C
  6:         11391         273384  java.lang.Long
  7:          5576         267648  java.util.TreeMap
  8:            50         155872  [I
  9:          6124         146976  java.lang.String
 10:          3330         133200  java.util.LinkedHashMap$Entry
 11:          5544         133056  javax.management.openmbean.CompositeDataSupport

执行 jmap -dump 可以转储堆内存快照到指定文件,比如执行 jmap -dump:format=b,file=/data/jvm/dumpfile_jmap.hprof 3361 可以把当前堆内存的快照转储到dumpfile_jmap.hprof文件中,然后可以对内存快照进行分析。

④利用jconsole、jvisualvm分析内存信息(各个区如Eden、Survivor、Old等内存变化情况),如果查看的是远程服务器的JVM,程序启动需要加上如下参数:

"-Dcom.sun.management.jmxremote=true" 
"-Djava.rmi.server.hostname=12.34.56.78" 
"-Dcom.sun.management.jmxremote.port=18181" 
"-Dcom.sun.management.jmxremote.authenticate=false" 
"-Dcom.sun.management.jmxremote.ssl=false"

下图是jconsole界面,概览选项可以观测堆内存使用量、线程数、类加载数和CPU占用率;内存选项可以查看堆中各个区域的内存使用量和左下角的详细描述(内存大小、GC情况等);线程选项可以查看当前JVM加载的线程,查看每个线程的堆栈信息,还可以检测死锁;VM概要描述了虚拟机的各种详细参数。(jconsole功能演示) 

Warum benötigt JVM eine Leistungsoptimierung?

下图是jvisualvm的界面,功能比jconsole略丰富一些,不过大部分功能都需要安装插件。概述跟jconsole的VM概要差不多,描述的是jvm的详细参数和程序启动参数;监视展示的和jconsole的概览界面差不多(CPU、堆/方法区、类加载、线程);线程和jconsole的线程界面差不多;抽样器可以展示当前占用内存的类的排行榜及其实例的个数;Visual GC可以更丰富地展示当前各个区域的内存占用大小及历史信息(下图)。(jvisualvm功能演示) 

Warum benötigt JVM eine Leistungsoptimierung?

⑤分析堆转储快照

前面说到配置了 “-XX:+HeapDumpOnOutOfMemory” 参数可以在程序发生内存溢出时dump出当前的内存快照,也可以用jmap命令随时dump出当时内存状态的快照信息,dump的内存快照一般是以.hprof为后缀的二进制格式文件。 
可以直接用 jhat(JVM Heap Analysis Tool) 命令来分析内存快照,它的本质实际上内嵌了一个微型的服务器,可以通过浏览器来分析对应的内存快照,比如执行 jhat -port 9810 -J-Xmx4G /data/jvm/dumpfile_jmap.hprof 表示以9810端口启动 jhat 内嵌的服务器:

Reading from /Users/dannyhoo/data/jvm/dumpfile_jmap.hprof...
Dump file created Fri Aug 03 15:48:27 CST 2018
Snapshot read, resolving...
Resolving 276472 objects...
Chasing references, expect 55 dots.......................................................
Eliminating duplicate references.......................................................
Snapshot resolved.
Started HTTP server on port 9810
Server is ready.

在控制台可以看到服务器启动了,访问 http://127.0.0.1:9810/ 可以看到对快照中的每个类进行分析的结果(界面略low),下图是我随便选择了一个类的信息,有这个类的父类,加载这个类的类加载器和占用的空间大小,下面还有这个类的每个实例(References)及其内存地址和大小,点进去会显示这个实例的一些成员变量等信息: 

Warum benötigt JVM eine Leistungsoptimierung?

jvisualvm也可以分析内存快照,在jvisualvm菜单的“文件”-“装入”,选择堆内存快照,快照中的信息就以图形界面展示出来了,如下,主要可以查看每个类占用的空间、实例的数量和实例的详情等: 

Warum benötigt JVM eine Leistungsoptimierung?

还有很多分析内存快照的第三方工具,比如eclipse mat,它比jvisualvm功能更专业,出了查看每个类及对应实例占用的空间、数量,还可以查询对象之间的调用链,可以查看某个实例到GC Root之间的链,等等。可以在eclipse中安装mat插件,也可以下载独立的版本(http://www.eclipse.org/mat/downloads.php ),我在mac上安装后运行起来老卡死~下面是在windows上的截图(MAT功能演示):

Warum benötigt JVM eine Leistungsoptimierung?

(3) JVM-Tuning-Erfahrung

In Bezug auf die JVM-Konfiguration können Sie im Allgemeinen zuerst die Standardkonfiguration verwenden (einige grundlegende Anfangsparameter können sicherstellen, dass allgemeine Anwendungen während des Tests stabiler laufen). Abhängig vom Betriebsstatus des Systems (Sitzungsgleichzeitigkeit, Sitzungszeit usw.) können in Kombination mit GC-Protokollen, Speicherüberwachung, verwendeten Garbage Collectors usw. angemessene Anpassungen vorgenommen werden. Wenn der Speicher der alten Generation zu klein ist, kann dies zu häufigen Volllastungen führen GC. Wenn der Speicher zu groß ist, ist die vollständige GC-Zeit extrem lang.

Was ist also die am besten geeignete JVM-Konfiguration, z. B. die neue Generation und die alte Generation? Die Antwort ist nicht unbedingt der Prozess, die Antwort zu finden. Wenn der physische Speicher sicher ist, gilt: Je größer die neue Generation, desto kleiner die alte Generation, desto höher ist die vollständige GC-Zeit. Im Gegenteil, die Einstellung der neuen Generation: Je kleiner sie ist, desto größer ist die alte Generation und desto geringer ist die Häufigkeit des vollständigen GC, aber desto mehr Zeit verbraucht jeder vollständige GC. Die Vorschläge lauten wie folgt:

  • Die Werte von -Xms und -Xmx sind standardmäßig auf die durch -Xms angegebene Größe eingestellt Der Heap-Speicher beträgt weniger als 40 %, die JVM erweitert den Heap auf die durch -Xmx angegebene Größe. Wenn der freie Heap-Speicher größer als 70 % ist, reduziert die JVM den Heap auf die durch -Xms angegebene Größe. Wenn der Speicherbedarf nach der vollständigen GC nicht gedeckt werden kann, wird er dynamisch angepasst. Diese Phase ist relativ ressourcenintensiv.

  • Die neue Generation sollte so groß wie möglich sein, damit Objekte in der neuen Generation über einen längeren Zeitraum überleben können. Jeder Minor GC muss so viele Müllobjekte wie möglich sammeln Verhindern oder verzögern Sie den Eintritt von Objekten in die alte Generation. Möglichkeit, die Häufigkeit von Full GC in Ihrer Anwendung zu reduzieren.

  • Wenn Sie den CMS-Kollektor der alten Generation verwenden, muss die neue Generation nicht zu groß sein, da die parallele Erfassungsgeschwindigkeit von CMS und die gleichzeitige Markierung ebenfalls sehr hoch sind und gleichzeitige Löschphasen des Erfassungsprozesses sind zeitaufwändig. Kann gleichzeitig mit Benutzer-Threads ausgeführt werden.

  • Festlegen der Größe des Methodenbereichs. Vor 1.6 müssen Sie die Konstanten, statischen Variablen usw. berücksichtigen, die dynamisch hinzugefügt werden, wenn das System ausgeführt wird muss in der Lage sein, die Klasseninformationen aufzunehmen, die beim Start und später dynamisch geladen werden.

In Bezug auf die Code-Implementierung sind Leistungsprobleme wie Programmwartezeiten und Speicherlecks nicht nur mögliche Probleme bei der JVM-Konfiguration, sondern haben auch viel mit der Code-Implementierung zu tun:

  • Vermeiden Sie die Erstellung übermäßig großer Objekte und Arrays: Übermäßig große Objekte oder Arrays gelangen direkt in die alte Generation, wenn die neue Generation nicht über genügend Platz verfügt, um sie aufzunehmen. Wenn es sich um kurzlebige große Objekte handelt, Die vollständige GC beginnt früh.

  • Vermeiden Sie das gleichzeitige Laden einer großen Datenmenge, z. B. das gleichzeitige Abrufen einer großen Datenmenge aus der Datenbank oder das gleichzeitige Lesen einer großen Anzahl von Datensätzen aus Excel Sie können die Referenzen schnellstmöglich einlesen und löschen.

  • Wenn Verweise auf Objekte in der Sammlung vorhanden sind, müssen die Verweise in der Sammlung so schnell wie möglich gelöscht werden, nachdem diese Objekte verwendet wurden. Diese nutzlosen Objekte müssen so schnell wie möglich recycelt werden um den Eintritt ins hohe Alter zu vermeiden.

  • Sie können Soft-Referenzen und schwache Referenzen in geeigneten Szenarien verwenden (z. B. bei der Implementierung von Caching), z. B. indem Sie Soft-Referenzen verwenden, um Instanzen von ObjectA zuzuweisen: SoftReference objectA=new SoftReference(); Speichergenerierung Vor dem Überlauf wird ObjektA in den Recyclingbereich für das sekundäre Recycling aufgenommen. Wenn für dieses Recycling nicht genügend Speicher vorhanden ist, wird eine Speicherüberlaufausnahme ausgelöst.
    Vermeiden Sie das Erstellen einer Endlosschleife. Nach dem Auftreten einer Endlosschleife kann es passieren, dass eine große Anzahl von Instanzen im Schleifenkörper wiederholt generiert wird, wodurch der Speicherplatz schnell voll wird.

  • Versuchen Sie, lange Wartezeiten auf externe Ressourcen (Datenbanken, Netzwerke, Geräteressourcen usw.) zu vermeiden, verkürzen Sie den Lebenszyklus von Objekten und vermeiden Sie den Eintritt ins hohe Alter. Wenn die Ergebnisse nicht rechtzeitig zurückgegeben werden können, können Sie sie entsprechend verwenden asynchrone Verarbeitungsmethoden usw.

(4) JVM-Fehlerbehebungsdatensatzfall

JVM-Dienst-Fehlerbehebung https://blog.csdn.net/jacin1/article/details/44837595

Unvergessliche Fehlerbehebung bei häufigen Full-GC-Prozessen http://caogen81.iteye.com/blog/1513345

Häufige Fehlerbehebung bei Online-Full-GC https://blog.csdn.net/wilsonpeng3 /article/details/70064336 /

[JVM] Fehlerbehebung bei Online-Anwendungen https://www.cnblogs.com/Dhouse/p/7839810.html

Eine Fehlerbehebung von FullGC im JVM-Prozess http://iamzhongyong.iteye .com/blog/1830265

Fehlerbehebung bei übermäßiger CPU-Auslastung durch JVM-Speicherüberlauf https://blog.csdn.net/nielinqi520/article/details/78455614

Eine Fehlerbehebung bei Java-Speicherlecks Fall https://blog.csdn.net/aasgis6u/article/details/54928744

(5) Allgemeine JVM-Parameterreferenz:

参数 说明 实例
-Xms 初始堆大小,默认物理内存的1/64 -Xms512M
-Xmx 最大堆大小,默认物理内存的1/4 -Xms2G
-Xmn 新生代内存大小,官方推荐为整个堆的3/8 -Xmn512M
-Xss 线程堆栈大小,jdk1.5及之后默认1M,之前默认256k -Xss512k
-XX:NewRatio=n 设置新生代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 -XX:NewRatio=3
-XX:SurvivorRatio=n 年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:8,表示Eden:Survivor=8:1:1,一个Survivor区占整个年轻代的1/8 -XX:SurvivorRatio=8
-XX:PermSize=n 永久代初始值,默认为物理内存的1/64 -XX:PermSize=128M
-XX:MaxPermSize=n 永久代最大值,默认为物理内存的1/4 -XX:MaxPermSize=256M
-verbose:class 在控制台打印类加载信息  
-verbose:gc 在控制台打印垃圾回收日志  
-XX:+PrintGC 打印GC日志,内容简单  
-XX:+PrintGCDetails 打印GC日志,内容详细  
-XX:+PrintGCDateStamps 在GC日志中添加时间戳  
-Xloggc:filename 指定gc日志路径 -Xloggc:/data/jvm/gc.log
-XX:+UseSerialGC 年轻代设置串行收集器Serial  
-XX:+UseParallelGC 年轻代设置并行收集器Parallel Scavenge  
-XX:ParallelGCThreads=n 设置Parallel Scavenge收集时使用的CPU数。并行收集线程数。 -XX:ParallelGCThreads=4
-XX:MaxGCPauseMillis=n 设置Parallel Scavenge回收的最大时间(毫秒) -XX:MaxGCPauseMillis=100
-XX:GCTimeRatio=n 设置Parallel Scavenge垃圾回收时间占程序运行时间的百分比。公式为1/(1+n) -XX:GCTimeRatio=19
-XX:+UseParallelOldGC 设置老年代为并行收集器ParallelOld收集器  
-XX:+UseConcMarkSweepGC 设置老年代并发收集器CMS  
-XX:+CMSIncrementalMode 设置CMS收集器为增量模式,适用于单CPU情况。  

Dieser Artikel stammt von der chinesischen PHP-Website, Spalte Java-Tutorial, willkommen zum Lernen!

Das obige ist der detaillierte Inhalt vonWarum benötigt JVM eine Leistungsoptimierung?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn