前言
所有的配置都是笔者所了解的,欢迎读者进行补充。
环境:jdk1.8
常用配置
推荐配置
-XX:-HeapDumpOnOutOfMemoryError默认关闭,建议开启,在java.lang.OutOfMemoryError异常出现时,输出一个dump文件,记录当时的堆内存。-XX:HeapDumpPath=./java_pid<pid>.hprof用来设置堆快照的存储文件路径,默认是java进程启动位置。- -Xmx用来控制最多堆空间。
调试
- -XX:+PrintGC 打印简单的GC信息。默认关闭。
- -XX:+PrintGCDetails 打印详细的GC信息。默认关闭。
- -XX:+PrintGCDateStamps 打印GC发生的时间。
-Xloggc:<filename>指定gc日志重定向到指定文件
-XX:+PrintGCDetails
我们使用在《JVM之内存结构》的逃逸分析的例子,进行分析下(使用的配置java -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xmx500m -Xms500m,设置的Xmx和Xms的目的是输出的信息比较好理解 ):
/**
* 逃逸分析-栈上分配
* -XX:-DoEscapeAnalysis
*/
public class EscapeAnalysisTest {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 50000000; i++) {//5000万次---5000万个对象
allocate();
}
System.out.println((System.currentTimeMillis() - start) + " ms");
Thread.sleep(3000);
}
static void allocate() {//逃逸分析(不会逃逸出方法)
//这个myObject引用没有出去,也没有其他方法使用
MyObject myObject = new MyObject(2020, 2020.6);
}
static class MyObject {
int a;
double b;
MyObject(int a, double b) {
this.a = a;
this.b = b;
}
}
}
日志输出:
//发生minor gc的时候年轻代从125.5M回收到还剩余0.45M 总的堆空间从125.5M回收到还剩余0.45M 实际消耗了0.01秒
2022-03-12T22:41:28.457-0800: [GC (Allocation Failure) [PSYoungGen: 128512K->464K(149504K)] 128512K->464K(491008K), 0.0051801 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2022-03-12T22:41:28.493-0800: [GC (Allocation Failure) [PSYoungGen: 128976K->432K(149504K)] 128976K->440K(491008K), 0.0006600 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.502-0800: [GC (Allocation Failure) [PSYoungGen: 128944K->448K(149504K)] 128952K->456K(491008K), 0.0006161 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.510-0800: [GC (Allocation Failure) [PSYoungGen: 128960K->368K(149504K)] 128968K->376K(491008K), 0.0005145 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.520-0800: [GC (Allocation Failure) [PSYoungGen: 128880K->432K(149504K)] 128888K->440K(491008K), 0.0006140 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.528-0800: [GC (Allocation Failure) [PSYoungGen: 128944K->416K(169984K)] 128952K->424K(511488K), 0.0005380 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.555-0800: [GC (Allocation Failure) [PSYoungGen: 169888K->0K(169984K)] 169896K->308K(511488K), 0.0006665 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2022-03-12T22:41:28.576-0800: [GC (Allocation Failure) [PSYoungGen: 169472K->0K(168960K)] 169780K->308K(510464K), 0.0003318 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//程序打印的日志
191 ms
//最后一次GC的时候堆的情况
Heap
//年轻代占用总空间165M 使用了69M
PSYoungGen total 168960K, used 70715K [0x00000007b5980000, 0x00000007c0000000, 0x00000007c0000000)
//eden区占用164.5M 使用了41%
eden space 168448K, 41% used [0x00000007b5980000,0x00000007b9e8edc0,0x00000007bfe00000)
//from区 占用了0.5M 使用了0%
from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
//to区 占用了1M 使用l0%
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
//老年代占用了 333.5M 使用了308k
ParOldGen total 341504K, used 308K [0x00000007a0c00000, 0x00000007b5980000, 0x00000007b5980000)
//对象空间333.5M 使用了0%
object space 341504K, 0% used [0x00000007a0c00000,0x00000007a0c4d060,0x00000007b5980000)
// 元空间(包括类空间和非类空间(常量池、JIT产生的一些东西等)) 使用了2.47M 实际分配的chunk大小4.38M 分配的chunk大小4.75M 空间总和1032M
Metaspace used 2531K, capacity 4490K, committed 4864K, reserved 1056768K
//类空间 使用了271k 实际分配的chunk大小0.37M 分配的chunk大小0.5M 空间总和1024M
class space used 271K, capacity 386K, committed 512K, reserved 1048576K
老年代和年轻代总的空间约等于指定的500M。发生了8次minor gc,最后一次显示年轻代已经全部回收完,老年代使用了308k,但是不是对象使用的空间,应该还有一些字符串常量池(jdk1.7及之后移动到堆内)等。eden survivor的比例不是8,因为默认开启动态分配。
元空间用来存放类元信息和常量池、JIT产生的一些东西等,used、capacity、committed、reserved具体参考
需要知道的
- -XX:+PrintFlagsFinal –version 参看jvm参数配置信息命令
- -Xss 线程栈默认分配1k。
- -Xms 最小堆空间,默认128M。
- -Xmx 最大堆空间,默认2G。
- -XX:MaxDirectMemorySize 默认为0
- -XX:SurvivorRatio 对年轻代进行划分比例,默认为8,Eden区占8/10。
- -XX:+UsePSAdaptiveSurvivorSizePolicy 默认开启,根据情况动态划分比例。
- -XX:+MaxTenuringThreshold 默认15,控制年轻代的对象在survivor区中来回被复制多少次后进入老年代
- -XX:TargetSurvivorRatio 默认50%。如果survivor区中的对象占用了多少空间后,较高复制次数的对象会进入老年区。
- -XX:+PrintCommandLineFlags -version 打印出现在命令行上的标志。
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
默认使用ParallelGC垃圾收集器。
可以用于优化的
-
-Xms:默认128M,可以设置大点,避免根据不足再动态调整产生gc。
-
-Xmx:默认为2G,服务器允许可以设置大点,避免不足产生gc。
-
-Xss:默认为1k,能放128个long变量,一般业务够了,但是jvm做了对象逃逸分析,不逃逸的可以直接在栈上分配,可以根据情况设置大点。
-
-XX:-UseBiasedLocking:用于禁用偏向锁,直接使用轻量锁。
因为生产环境如果使用了synchronized锁,大部分场景不存在只有一个线程竞争。如果有多个线程先后尝试进入临界区,第一个线程先持有偏向锁,第二个线程尝试进入的时候需要等待全局安全点,再暂停拥有偏向锁的线程,判断它是否还存活,死亡了就释放占用,还活着就升级为“轻量锁”,整个步骤其实很繁琐效率也不高。
-
-XX:MaxDirectMemorySize:默认为0,如果需要用到堆外内存需要设置。比如nio中使用
ByteBuffer.allocateDirect避免堆内堆外来回拷贝。 -
-XX:newSize:默认为40M,虽然会扩容可以根据情况分配大点,相当于预热避免前期的ygc。
-
-Dsun.reflect.inflationThreshold= 15 :默认达到15次时动态生成字节码对反射进行优化。可以设置小点或者使用
-Dsun.reflect.noInflation=true来关闭,直接生产字节码,一步优化。 -
-XX:MetaspaceSize=:默认为20M,可以根据情况设置大点,比如项目比较大,动态生成字节码的地方比较多,避免扩容耗时。
-
-XX:TypeProfileWidth:默认为2,虚方法内联记录类型数目,能使虚方法调用变快,可以根据情况设置大点。
-
垃圾收集器:默认
-XX:+UseParallelGC,可以使用-XX:+UseG1GC化整为零整体上不STW。