JVM
什么是JVM?
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
1.1、类加载器层级
- 启动类(根)加载器(BootstrapClassLoader):主要负责加载核心的类库java.base.jmod 中的class,构造ExtClassLoader和AppClassLoader。
- 扩展类加载器(ExtClassLoader)
- 应用程序加载器(系统类加载器)
1.2、双亲委派机制
保障运行安全
根加载器–>扩展类加载器–>应用程序加载器
委托机制
当一个类加载和初始化的时候,类仅在有需要加载的时候被加载。假设你有一个应用需要的类叫作abc.class,首先加载这个类的请求由 Application类加载器委托给它的父类加载器Extension类加载器,然后再委托给Bootstrap类加载器。Bootstrap类加载器 会先看看rt.jar中有没有这个类,因为并没有这个类,所以这个请求由回到Extension类加载器,它会查看jre/lib/ext目录下有没有这 个类,如果这个类被Extension类加载器找到了,那么它将被加载,而Application类加载器不会加载这个类;而如果这个类没有被 Extension类加载器找到,那么再由Application类加载器从classpath中寻找。记住classpath定义的是类文件的加载目 录,而PATH是定义的是可执行程序如javac,java等的执行路径。
可见性机制
根据可见性机制,子类加载器可以看到父类加载器加载的类,而反之则不行。所以下面的例子中,当Test2.class已经被Application类加 载器加载过了,然后如果想要使用Extension类加载器加载这个类,将会抛出java.lang.ClassNotFoundException异常。
public class Test2 {
public static void main(String[] args) {
try {
Class.forName("com.dushu817.exprise.javaexprise.classloader.Test2", true, Test2.class.getClassLoader().getParent());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
单一性机制
根据这个机制,父加载器加载过的类不能被子加载器加载第二次。虽然重写违反委托和单一性机制的类加载器是可能的,但这样做并不可取。你写自己的类加载器的时候应该严格遵守这三条机制。
1.3、沙箱安全机制
2、Native
出现native关键字,说明java会去调用底层的c语言库
会进入本地方法栈 (Native Method Stack)———>本地方法接口(JNI)———>调用本地方法库
3、PC寄存器
程序计数器:Program Counter Register
每个前程都有一个程序计数器,是线程私有的,本质是一个指针,指向方法区中的方法字节码(用来存储指向一条指令的地址,以及即将要执行的指令代码),在执行引擎读取下一条指令。空间非常小。
4、方法区
方法区:Method Area
方法区是被所用线程共享的。
5、堆
堆内存中细分为三个区
- 新生区
- 伊甸园区
- 幸存者区
- 幸存者0区
- 幸存者1区
- 养老区
- 永久区(jdk8以后 叫 元空间)
5.1、新生区
6、GC
6.1 、垃圾回收(Garbage Collection)
负责回收堆内存heap中没有被使用的对象判断对象是否存活、可达性检测
- 引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加1,当引用失效时,计数器值就减1。任何时刻计数器为0的对象就是不可能再被使用的
- GC ROOT:通过一系列名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连接时,就证明此对象是不可用的
6.2、 垃圾回收算法
1)标记清除算法(Mark-Sweep)
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象
- 效率问题:标记清除都不是高效动作
- 空间问题:标记清除之后产生大量不连续的内幕才能碎片,碎片太多导致分配较大对象时无法找到足够的连续内存而不得不提前触发另一次GC
2)复制算法Copying
它将可用内存按容量划分为大小相等的两块,每次只是用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清除掉
- 可用内存缩小为原来的一半
- 每次收集时,所有的标记对象都要被拷贝,从而导致一些生命周期很长的对象被来回拷贝多次,消耗大量的时间(分代回收来解决这个问题)
3)分代回收算法(Generational Collecting)
根据对象存活周期的不同将内存划分为几块
- 新生代:内存分为一块较大的Eden控件和两块较小的Survivor空间。新建object在Eden,Eden满时触发GC,Eden中存活对象别移动到S0区,清空Eden;等Eden再满再GC,Eden和s0中的存活对象被复制到s1(复制算法保证了s1中来自Eden和s0两部分的存活对象占用连续的内存空间,避免了碎片化);清空Eden和s0。
下一轮的时候s0和s1交换角色,如此循环往复。
如果对象的复制次数达到15次,该对象就会被送到老年代 - 老年代:对象存活率高
- 垃圾回收器(垃圾回收算法的具体实现)
- 并行与并发
- **并行Parallel:**指多条垃圾收集线程并行工作,但此时用户线程扔处于等待状态
- 并发Concurrent:指用户线程与垃圾收集线程同时执行,用户程序在继续运行,而垃圾收集程序运行在另一个CPU上
- 新生代Minor GC:新生代内存不大,回收速度比较快
- 老年代Major GC/Full GC:内存一般比较大,用于缓存大对象,回收速度约Minor GC的10倍以上
- 吞吐量Throughput:JVM总共运行了100分钟,其中垃圾回收机花掉1分钟,那吞吐量就是99%
- 停顿时间:垃圾回收器正在运行时,应用程序的暂停时间(for streaming pipeline)
4)回收类型
- NEW
- serial:单线程
- parNew:serial多线程版本
- Parallel Scavenge:复制算法,并行,优先保证吞吐量,不顾及用户STW感受,吞吐量方面优化的系统,停顿时间长是可以接收的
- Old/tenured
- Serial Old:serial回收器的老年代版本,单线程,标记-整理算法
- Parallel Old:Parallel Scavenge回收器的老年代版本,多线程,标记-整理算法
- Concurrent Mark Sweep(CMS):优先最短回收停顿时间,用户体验好,标记-清除算法
- New and Old
- 关键点:region内存划分,优先级区域回收方式。优先回收价值最大的region
- Garbage First(G1):它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,他们都是一部分Region(不需要连续)的集合。
6.3、jvm调优命令
-Xmx1024m -Xms1024m -Xmn512m -Xss256k——JVM运行参数
JVM的堆的内存, 是通过下面面两个参数控制的
-Xms 最小堆的大小, 也就是当你的虚拟机启动后, 就会分配这么大的堆内存给你
-Xmx 是最大堆的大小
当最小堆占满后,会尝试进行GC,如果GC之后还不能得到足够的内存(GC未必会收集到所有当前可用内存),分配新的对象,那么就会扩展堆,如果-Xmx设置的太小,扩展堆就会失败,导致OutOfMemoryError错误提示。
实际上,细节不止于此, 堆还会被分成几个不同的区域,分别应用不同的GC算法
6.3.1、JVM调优-Xms -Xmx -Xmn -Xss
堆大小设置
JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。
6.3.2、调优示例
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550M。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k: 设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内 存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
回收器选择
JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置进行判断。
吞吐量优先的并行收集器
6.3.3、辅助信息设置
JVM提供了大量命令行参数,打印JVM运行时的信息:
-XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
-XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间。可与上面混合使用
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
-Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。
6.3.4、JVM常见参数配置
堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
6.4、垃圾回收器开启命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eELDALT-1668519787998)(C:\Users\mzj18\AppData\Roaming\Typora\typora-user-images\image-20220913203112664.png)]
6.5、默认的垃圾回收器(Default Garbage Collections)
- Java 7 - Parallel GC
- Java 8 - Parallel GC
- Java 9 - G1 GC
式为并行收集时,使用的CPU数。并行收集线程数。
6.4、垃圾回收器开启命令
6.5、默认的垃圾回收器(Default Garbage Collections)
- Java 7 - Parallel GC
- Java 8 - Parallel GC
- Java 9 - G1 GC