JIT即时编译器
JIT(Just In Time) 即时编译器
- 对于所有的应用都应该使用server编译器和分层编译
- 只要保证代码缓存足够大,编译器就能够提供尽善尽美的性能
代码缓存
通常只需要设置代码缓存的最大值:-XX:ReservedCodeCacheSize,代码缓存的初始大小(-XX:InitialCodeCacheSize)JVM会自动帮你设置,缓存的大小会在后台自动调整。
java -jar -XX:ReservedCodeCacheSize=240m yeti-apiapp-1.0.jar
编译阈值
client编译器默认值1500,server编译器默认值10000,更改CompileThreshold会使编译器提前或延后编译,所以一定要根据需求进行设置。
java -jar -XX:CompileThreshold=10000 yeti-apiapp-1.0.jar
检测编译过程
开启PrintCompilation,每次编译一个方法或循环时,JVM就会打印一行被编译的内容信息
java -jar -XX:+PrintCompilation yeti-apiapp-1.0.jar
jstat -compiler 5040
jstat -printcompilation 5040 1000
编译线程
java -jar -XX:CICompilerCount=4 yeti-apiapp-1.0.jar
垃圾收集入门
**Minor GC的原理:**新生代填满时,垃圾收集器会暂停所有的应用线程,回收Young Generation空间,不再使用的对象会被回收,仍在使用的对象会移到Survivor或者Old Generaton中,对于这种操作我们称为Minor GC。
Serial GC
Clinet型虚拟机,Serial使用单线程清理堆的内容,进行Minor GC和Full GC时,所用应用线程都会被暂停。
开启:-XX:+UseSerialGC,默认情况下时开启的。
关闭:关闭可以通过指定另外一种垃圾收集器实现。
Throughput GC
Server型虚拟机的默认收集器,Throughput使用多线程清理堆内容,进行Minor GC和Full GC时,所用应用线程都会被暂停。
在进行Full GC时会对老年代空间进行压缩整理。
开启:默认开启,-XX:+UseParallelGC,-XX:+UseParallelOldGC
CMS GC
Minor GC阶段,暂停应用线程,使用多线程进行回收,使用全新的算法(-XX:+UseParNewGC)。
Old Generation的回收,使用多个线程定期的对Old Generation空间进行扫描,及时回收不再使用的空间。
应用程序线程停顿的总时长比Throughput短得多。
缺点:
- 使用更多的CPU。
- 不进行压缩整理工作,导致堆碎片化,过度碎片化会退化到Serial收集器行为。
G1 GC
适合于超大堆,降低stop-the-world。
G1将堆划分若干个区域(Region)。
G1收集器实现了堆的部分压缩整理,相比CMS不容易发生Full GC。
开启:
java -jar -Xms6144m -Xmx6144m -XX:+UseG1GC yeti-apiapp-1.0.jar
java -jar -XX:+UseG1GC yeti-apiapp-1.0.jar
调整堆大小
- JVM会根据运行的机器,尝试估算最小、最大堆。
- 尽量不要调整堆的大小,除非需要比默认值更大的堆。
- 如果确定应用程序需要多大的堆,可以将堆的初始值和最大值设置成相同大小(-Xms1024m -Xmx1024m),此方法不需要估算堆是否需要调整大小,因此可以稍微提高GC运行效率。
java -jar -Xms1024m -Xmx1024m yeti-apiapp-1.0.jar
调整代空间大小
所有调整代空间的标志,都是调整Young Generation空间,剩下的便是Old Generation的空间。
设置新生代空间占用比例,默认值2,经过计算新生代空间大小是初始堆大小的33%
-XX:NewRatio=N
Initial Young Gen Size = Initial Heap Size / (1 + NewRatio)
设置新生代空间初始大小-XX:NewSize=N
设置新生代空间最大大小-XX:MaxNewSize=N
设置初始大小和最大大小快捷方式-Xmn100m
如果堆的大小是确定的,可以指定代空间的最大值和最小值,否则最好使用-XX:NewRatio,按照比率调整。
调整元空间大小
JVM载入类的时候,类的元数据就会保存到元空间(Metaspace)。
-XX:MetaspaceSize=N-XX:MaxMetaspaceSize=N
调整并发线程数
-XX:ParallelGCTheads=N
开启GC日志功能
显式的输出
java -jar -XX:+PrintGCDetails yeti-apiapp-1.0.jar
通过日志形式输出
java -jar -XX:+PrintGCTimeStamps yeti-apiapp-1.0.jarjava -jar -XX:+PrintGCDateStamps yeti-apiapp-1.0.jar
输出GC详细日志到/usr/log方式
java -jar -Xloggc:/usr/log -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=1024 yeti-apiapp-1.0.jar
通过脚本的方式获取GC数据
jstat -gcutil 13668 1000
垃圾收集算法
理解Throughput垃圾收集器
理解CMS垃圾收集器
理解G1垃圾收集器
堆内存最佳实践
查看堆直方图
jcmd 13668 GC.class_histogram
原生内存最佳实践
原生内存跟踪
原生内存跟踪 Native Memory Tracking
Java8开始可以查看原内存使用情况
-XX:NativeMemoryTracking=off|summary|detail summary=概要模式 detail=详细模式
通过jcmd命令获取原生内存信息 jcmd process_id VM.native_memory sumary
java -XX:NativeMemoryTracking=summary -jar yeti-apiapp-1.0.jarjcmd 16768 VM.native_memory summary
Class - 保存类元数据
Thread - 66个线程,每一个大概1M空间
Code - JIT的代码缓存
Native Memory Tracking - NMT本身操作需要消耗一些内存
基线的使用
jcmd 16768 VM.native_memory baselinejcmd 16768 VM.native_memory summary.diff
线程与同步的性能
对于线程的性能来说,并没有太多可以调优的地方,可以设置的JVM标志非常的少,而且这些标志的作用也非常小,比如说线程栈大小的调节、偏向锁的设置、自旋锁方式配置、线程优先级调节,是完全没有必要的,甚至进行调节之后对于程序的运行有很大的影响。
查看线程
jconsole 15784
查看阻塞线程
jstack 15784
。