JVM概述
- JRE由Java虚拟机(Java Virtual Machine)和Java 应用编程接口(Application Programming Interface、简称API)构成(JDK1.8以上)。
-
能运行在JVM中的编程语言:Scala、Groovy、jruby、jython。
JVM工作流图
基础指令
#查看java进程号pid
$ jps
#查看正在运行的 java 应用程序的扩展参数,包括Java System属性和JVM命令行参数
$ jinfo -flag 参数 pid / jinfo -flags pid
#查看堆内存使用状况
$ jmap pid
#查看某个Java进程内的线程堆栈信息
$ jstack pid
#输出的是GC信息,采样时间间隔为250ms,采样数为10(不输入会一直采样)
$ jstat -gc pid 250 10
基础工具
- JDK自带的JVisualVM(输入指令
$jvisualvm
调出)
# dump出hprof文件可以用JVisualVM进行分析
$ jmap -dump:format=b,file=heap.hprof pid
jvisualvm分析hprof文件如果出现Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding的报错,是因为当前命令用户和程序执行的用户不一致,添加 sudo -u 程序执行用户名即可。
-
JDK自带的jconsloe(输入指令
jconsle控制台监控$jconsole
调出)
-
开源的Java诊断工具:阿里的Arthas(阿尔萨斯)
https://arthas.aliyun.com/doc/
JVM及GC参数
JVM参数调优配置说明
经典参数如下:
- -Xms20m 参数简写,相当于 -XX:InitialHepSize=20m 初始化堆空间大小,默认系统内存的1/64
- -Xmx1024m 参数简写,相当于 -XX:MaxHeapSize=1020m 最大堆空间大小,默认系统内存的1/4
- -Xss1024k => -XX:ThreadStackSize=1024k 单个线程栈大小
- -Xmn年轻代的大小
JVM堆空间
堆空间- jdk1.7中的常量池确实是移到了堆中,同时在jdk1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域。
- 元空间放在本地内存,使用
-XX:MaxMetaspaceSize
可以设置最大限制,默认不设上限为机器最大的内存,其存放的内容:
- 类的信息
- 常量池
- 静态变量
- 即时编译器编译后的代码(class字节文件)
元空间溢出案例(参数:-XX:MaxMetaspaceSize=10m)
// 不停的反射生成代理类
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DemoApplication.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
// 异常信息
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:563)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:582)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:569)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:384)
GC收集器
- Serial 串行(client模式[内存小于2G或者单核等低配置]老年代默认)-XX:+UseSerialGC
- Parallel 并发(server模式新生代默认)-XX:+UseParNewGC
- CMS 并行(ConcurrentMarkSweep)最短stw时间 -XX:+UseConcMarkSweepGC
- 此时SerialOld作为后备收集器(担保机制)【old满时,出现大停顿】
过程:初始标记(stw)、并发标记、重新标记(stw)、并发清除
优点:更短的STW时间;缺点:产生碎片
- G1 1.9后默认(GabageFirst) Region块 单个 1~32M 最多2048块 +XX:+UseG1GC
GC对比过程:初始标记(stw)、并发标记、最终标记(stw)、筛选回收(stw)
优点:stw可配,不产生碎片
经验&规则
1、堆空间默认比例与年龄
默认young {eden:from:to = 8:1:1 -XX:SurvivorRatio=8} : old 1/3 -XX:NewRatio=3
默认-XX:maxTenuringThreshold=15 young到old年龄 (0-15之间)
2、年轻代大小选择
- 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
- 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
- 避免设置过小。当新生代设置过小时会导致:YGC次数更加频繁,可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC。
3、年老代大小选择
- 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。
- 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
网友评论