JVM : 一个能运行java 字节码文件的机器,只要能够生成正常的字节码文件,不管是python,kotlin 都没关系。
JVM基本结构:类加载系统,运行时数据区,执行器。
类加载系统:1 加载class。2 linking。3 初始化。
a. 加载class 主要是三个类,applicationClassLoader, extentionClassLoader, bootstrapClassLoader. 这里有个概念叫双亲委派机制。主要是说类的加载首先是一层一层委托给上一级的加载器去加载的,比如,自定义的一个class,首先是到 acl, 在到ecl,在到bcl。然后bcl 看能不能加载,不能加载在给ecl 加载,ecl 也不能在给 acl。但这个模型可以被打破。比如DriverManager这个类是jdk提供的,正常来说这个类下面的方法都有bcl加载,但是驱动器的类一般都是其他厂商提供的,所以bcl 加载不了,需要acl 去加载。所以采用了加载驱动器的是用Class.forName(driver.getClass().getName(), true, classLoader);指定classLoader 为acl。这个机制我觉得目的其实是保护核心类库的安全,不让其他厂商修改jdk的核心类。
b.linking 主要分为3步:验证,准备,解析。验证主要是校验字节码文件正确性。准备主要是给类的静态变量分配内存,并给初始值。解析主要是类中引用其他类的解析。
c. 初始化 主要给静态变量赋予正确的值,并执行静态代码块。
运行时数据区:方法区,heap,stack,pc register,本地方法栈。
a.方法区包含类的所有字段,方法字节码,构造方法,接口定义,运行时常量等。
b.heap 存放具体对象实例。也是垃圾收集器主要工作的区域。
c.stack 线程执行的内存模型,一个线程对应一个栈,一个方法会对应一个栈帧,一个栈帧包含方法区的局部变量,动态链接,操作数类等。
d.pc 寄存器主要是存放指针 指向方法区的引用字节码。
e. 本地方法栈主要是和stack 类似,但是主要是jvm native方法。
执行器:jit compile,垃圾回收器等。
垃圾回收:在堆中的对象其实分为几个部分,一个是新生代,老年代,元数据。新生代中有分为eden和 suriver,eden 主要是产生对象区域,eden 满了就会产生 Minor gc 将 对象移动到 suriver ,suriver 又分为from 和 to ,对象一般先放在from ,然后在移动到to, to 也是有可能会转移到from。多次gc 还存在的对象就会挪到老年代。老年代的对象满了就会发生full gc。如果还是不释放资源,救护发生oom。元数据在逻辑上属于堆,但是物理上存储是属于本地内存。元数据区其实是方法区的实现。
上面其实介绍垃圾回收的工作空间,就是它gc 的区域,对象在不同时期存储的位置。但是对象什么情况会被gc。条件是什么呢?
第一种引用计数器。就是给对象添加一个标记,记录这个对象的引用的次数,有一个地方引用+1,引用失效-1。引用为0表示没有地方引用。这种方案简单,效率高,但无法解决循环引用的问题。
第二种可达性分析算法。主要是给对象设置了GC roots 的概念,这个GC root挂的是对象链表。如果对象没有了GC root 说明这个链表的对象都可以被gc。但如何设置这些root 呢 ?类加载器、Thread、虚拟机栈的局部变量表、static成员、常量引用、本地方法栈的变量等。
回收算法:标记清除算法。复制算法。标记-整理算法。分代收集算法。
标记清除算法:分为2步,第一步标记,第二部清除,在标记完成后进行统一的回收。这种回收效率低,空间回收都是不连续的。
复制算法:将空间分成2部分,一部分存储对象,标记对象。另一部分保留空间。第一部分需要回收和标记清除算法一致,清除完毕后将保留空间和使用空间对调,然后对之前使用空间进行整理。
标记整理算法:这个算法只标记了可回收对象,但是没有直接对可回收对象进行回收,而是对存活对象向前移动一段距离,然后将边界资源全部清除。
分代回收算法:这个主要是根据新生代和老年代不同对象区域采用不同的算法,比如新生代 回收有带大部分对象需要回收可以采用复制算法,老年代就比较少对象需要回收,可以采用标记整理的算法。
垃圾收集器:Serial收集器,ParNew收集器,Parallel Scavenge收集器(JDK1.8),G1 收集器。垃圾收集器的工作原理暂时不进行深入研究,基本上也是采用以上几种算法。如何选择垃圾收集器,其实生产环境主要是是配置堆大小,让JVM 自动选择。官方推荐是G1。
JVM 如何调优?
首先得学会使用查看一下信息的工具,比如Jinfo,Jstat,Jmap,Jstack等命令行工具。-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
- 打印gc 日志。
- 分析关键性指标。
- 调整jvm 参数
-Xss:每个线程的栈大小
-Xms:初始堆大小,默认物理内存的1/64
-Xmx:最大堆大小,默认物理内存的1/4
-Xmn:新生代大小
-XX:NewSize:设置新生代初始大小
-XX:NewRatio:默认2表示新生代占年老代的1/2,占整个堆内存的1/3。
-XX:SurvivorRatio:默认8表示一个survivor区占用1/8的Eden内存,即1/10的新生代内存。
-XX:MetaspaceSize:设置元空间大小
-XX:MaxMetaspaceSize:设置元空间最大允许大小,默认不受限制,JVM Metaspace会进行动态扩展。