一、JVM
Java Virtual Machine,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的
l一套字节码指令集(执行引擎)
l一组寄存器
l一个栈
l一个垃圾回收堆
l一个存储方法域
l一个本地方法栈
l一套调用本地方法的接口
pJVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行
二、常见关于JVM的异常
- java.lang.OutOfMemoryError: PermGen space:Java虚拟机对永久代Perm内存设置不够( Java反射大量使用常见)
JDK1.8之后看不到这个错了!
- java.lang.OutOfMemoryError: java heap space :Java虚拟机对堆内存设置不够 (内存泄漏:常见的集合对象引用)
- java.lang.StackOverflowError :Java虚拟机对栈内存设置不够(递归没返回,或者循环调用造成)
- Fatal: Stack size too small:栈空间太小
- java.lang.OutOfMemoryError: unable to create new native thread:操作系统没有足够的资源来产生这个线程(可以通过修改-Xss来减少分配给单个线程的空间)
三、JVM的种类
- HotSpot VM(主流)
- Oracle / Sun JDK、OpenJDK的各种变种(例如IcedTea、Zulu)用的都是相同核心的HotSpot VM,
在没有特殊说明的情况下说jvm实现原理一般均指HotSpot VM
- JDK8的HotSpot VM已经是以前的HotSpot VM与JRockit VM的合并版,也就是传说中的“HotRockit”,只是产品里名字还是叫HotSpot VM(移除PermGen )
- J9 VM
J9是IBM开发的一个高度模块化的JVM
- 淘宝定制 JVM:TaobaoJVM
TaobaoJVM 基于 OpenJDK HotSpot VM,是国内第一个优化、定制且开源的服务器版Java虚拟机。目前已经在淘宝、天猫上线,全部替换了Oracle官方JVM版本,在性能,功能上都初步体现了它的价值
- BEA Jrockit
Java SE的主流JVM中还有JRockit,跟HotSpot与J9一起并称三大主流JVM
四、JVM工作机制
五、Javac 执行原理
六、JVM结构
七、JVM共享数据空间
- JVM共享数据空间主要三大块:新生代、老年代、方法区
- 新生代:Eden区存放新生对象、From\To Survivor 存放GC后存活的对象(8:1:1)
- 永久代管理类信息、静态对象、静态变量、常量、类属性、运行时常量池等
- JVM参数设置:heap的大小( Xms堆的最小值、 Xmx堆空间的最大值 )、永久代 大小(-XX:MaxPermSize )
- NewRadio:设置新生代与老年代的比例,默认为1:2
- 所有线程共享:在堆上对象内存分配时需要加锁,导致new 一个对象时开销比较大,所以尽量避免重复new对象。
八、JDK版本下JVM的变化
- JDK 1.7 :
已经将原本放在永久代的字符串常量池移走
- JDK1.8 :
1、对 JVM 架构的改造将类元数据放到本地内存中,
2、将常量池和静态变量放到 Java 堆里。
3、HotSopt VM 将会为类的元数据明确分配和释放本地内存
4、 -XX:MaxPermSize 配置无意义了
5、进一步避免Full GC
九、JVM调优
常用JVM参数
参数 |
说明 |
实例 |
-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情况。 |
|
十、JVM调优策略
根据业务系统指标调优
- 系统响应时间
l 需要立刻响应:可适当增加年轻代的大小
- 系统吞吐量
l 不是很在乎响应时间,提供并行事务的处理能力,可适当提高老年代的大小
十一、JVM调优工具
1、常用JVM调优工具
Jconsole,jProfile,VisualVM
- Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪
- JProfiler:商业软件,需要付费。功能强大
- VisualVM:JDK自带,功能强大,与JProfiler类似
注:建议使用VisualVM,在已经安装jdk并配置环境变量的window操作系统下,进入dos窗口,执行jvisualvm.exe 即可打开工具
2、生产环境常见JVM问题(Linux居多,且线上不宜像本地通过工具分析)
- 内存泄露
- 某个进程突然cpu飙升
- 线程死锁
3、Linux线上JVM问题解决方式
- jps:jvm进程状况工具
- jstat: jvm统计信息监控工具(线上定位问题首选工具)
- jinfo: java配置信息(获取一些当前进程的jvm运行和启动信息)
- jmap: java 内存映射工具(打印出某个java进程(使用pid)内存内的,所有‘对象’的情况)
- jhat:jvm堆快照分析工具(不建议在线上直接使用,可以下载到本地使用)
- jstack:java堆栈跟踪工具