一.引言
- JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也叫虚拟计算机。操作系统运行JVM是通过jdk中Java.exe来完成的。
- 每个使用Java的开发者都知道Java字节码是在JRE中运行(JRE: Java 运行时环境)。JVM则是JRE中的核心组成部分,承担分析和执行Java字节码的工作,而Java程序员通常并不需要深入了解JVM运行情况就可以开发出大型应用和类库。
- java虚拟机(JVM:Java Virtual Machine)是通过软件模拟物理机器执行程序的执行器。最初Java语言被设计为基于虚拟机器在而非物理机器,重而实现WORA(一次编写,到处运行)的目的,尽管这个目标几乎被世人所遗忘。所以,JVM可以在所有的硬件环境上执行Java字节码而无须调整Java的执行模式。
二.内存结构
1.方法区 也称永久代
- 存放 类的信息,常量,静态变量
- 各线程共享
2.栈空间
- 存放局部变量,操作栈,方法出口等信息 (spring单例安全)
- 线程私有
- 栈帧固定大小分配,异常栈溢出
3.堆空间 也称“gc”
- 存放 对象实例及数组
- 线程共享
- 在JVM启动时创建
4.程序计数器
- 作用:当前线程所执行的字节码的行号指示器
- 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,异常处理
- 线程恢复等基础功能
三.JVM代划分
- 年轻代(Young Generation)
- 老年代(Old Generation)
- 永久代(Permanent Generation)
Heap(堆) = 年轻代 (eden + survivor1 + survivor2) + 老年代
四.触发GC和Full GC
- GC: 一般情况下,当新对象生成,且在Eden申请空间失败时,就会触发GC
- Full GC:
年老代写满
永久代写满
System.gc()被显式调用
五.垃圾回收算法
-
Mark-Sweep(标记 - 清除)算法
它是最基础的垃圾回收算法,其他算法都是基于这种思想。标记-清除算法分为“标记”,“清除”两个阶段:首先标记出需要回收的对象,标记完成后统一清除对象
缺点:
①:标记和清除的效率不高
②:标记之后会产生大量不连续的内存碎片 -
Coping(复制)算法
它将可用内存分为两块,每次只用其中的一块,当这块内存用完以后,将还存活的对象复制到另一块上面,然后再把已经使用的内存空间一次清理掉
优点:
①:不会产生内存碎片
②:只要移动堆顶的指针,按顺序分配内存即可,实现简单,运行高效
缺点:
①:内存缩小为原来的一半 -
Mark-Compact(标记 - 整理)算法
标记操作和”标记-清除“算法一样,后续操作变成不直接清理对象,而是在清理无用对象的时候完成让所有存活的对象都像一端移动,并更新对象的指针
优点:不会产生内存碎片
缺点:在“标记-清除”基础上还要进行对象的移动,成本相对较高 -
☆ Generational Collection(分代收集)算法
是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。
目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间而由于老年代的特点是每次回收都只回收少量对象,一般使用的是Mark-Compact算法。
注意,在堆区之外还有一个代就是永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。
六.优化参数配置
1、 堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小 -XX:NewSize=3
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=3
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 3:1:1
-XX:MaxPermSize=n:设置永久代大小
2、 收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
-XX:+UseG1GC 设置G1收集器
3、 垃圾回收统计信息
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
4、 并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
5、 并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
七.优化工具的启动虚拟机
1、 打开工具的.ini加入如下配置
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:D:\jvm.log
2、 查看jvm.log文件
查看触发了Gc Full Gc
3、 更改配置
-Xms3096m 设置堆最小空间
-Xmx3096m 设置堆最大空间
-XX:MaxPermSize=256m 设置永久代空间