JVM虚拟机调优的目的
- 减少 full gc 的次数
- 减少运行 full gc 的运行时间
Java虚拟机结构
类元信息:类的结构信息,就是线程中有哪些方法 有哪些信息
方法区用的内存是直接内存也就是本地内存(如果一个电脑的运行内存是16G,JVM用了1G剩下15G,那个方法区的内存就是在15G中)
静态变量是存储在方法区的,不过它的本体在 堆中,实际上它只存了一个指针
class Math{
public int compute(){
int a = 1;
int b = 2;
int c = (a+b)*10;
return c;
}
public static void main(String[] args){
Math math = new Math();
math.compute();
}
}
在new 对象的时候,在生成对象的时候会有一个 对象头 也会生成,这个对象头里有个非常重要的指针叫做:Klass pointer(类型指针) 它的作用是:类的元数据指针,指向了类元信息
对象new 完之后,对象头指向了这个类的 类元信息,从而获取了下一步该怎么走
在java虚拟机里面 对这些方法明有个称呼 叫做 静态的符号
当把一个符号 转换成 它所对应的代码指令码的时候(comput()符号 通过 math 找到 它的代码)
完整的Java虚拟机由这三块组成
- 类装载子系统
- 运行时数据区(内存模型)
- 执行引擎
Java虚拟机会把字节码文件 通过 类装载子系统 装载到内存区里 的方法区 里
再通过 执行引擎 执行方法区里的方法
执行main线程时,Java虚拟机会给main线程分配一块栈的内存空间,然后main线程中的每一个方法都在这块内存空间中有自己的内存区域 叫做 栈帧 每个方法对应了一块栈帧内存区域
程序计数器
里面放的是线程马上要执行的下一行或者现在要执行的那一行的JVM 指令码的地址指针 (行号)
执行引擎会更新程序计数器的值
栈帧的结构
int a = 1;
int b = 2;
int c =(a + b)* 3;
- 局部变量表:a,c,b
- 操作数栈:1,2,3
- 动态链接:在对象new出来之后,对象头指向了方法区的 类元信息,类元信息是一个类的结构和线程中有哪些方法,这样就可以找到 compute()方法 , 存储的是这个compute()的地址。这个执行码一定是程序运行过程中生成的地址
- 方法出口:在进到这个方法的时候就已经把程序计数器的值放到要执行的方法的方法出口中去了。存放的是 一旦一个方法执行完了返回到main方法对应的哪一行代码中去
运行步骤:
- 先把 1,押入到操作数栈
- 再把a 押入到局部变量表中
- 再把 1 从操作数栈拿出来 存到 a所在的局部变量表中的内存区域 (int b =2 也一样)
- 把 a = 1 的值,也就是1 拿出来 再次放到 操作数栈里
- 再把 2 拿出来 放到 操作数栈中
- 然后再执行int类型的 + 法 ,会从操作数栈的栈顶 弹出两个 最新的数做加法**(加法在执行引擎中操作)**
- 做完 加法后把结果 押回 操作数栈
在栈里面有很多局部变量,如果这个局部变量是对象类型的,那么就会指向堆里面不同的小对象
本地方法栈
private native void start0();
有native的方法就是本地方法
如果运行到native方法的时候,它就回去你操作系统对应的C语言函数库 (比如window就会去到C语言的函数库,去找一些像 xx.dll 的文件 类似于java中的jar包 ,它里面有这个native的实现)
本地方法的局部变量需要分配的内存 都 存储在 本地方法栈
GC Roots根
GC Roots根节点:类加载器,Thread,虚拟机栈的本地变量表,static成员,常量引用,本地方法栈的变量等等
math和math2 就算是 GC Roots根,当线程结束后 Java虚拟机把 局部变量表 的GC Roots结束的时候就失去指针了
堆
堆中的内存大小分配
- 年轻代占了三分之一
- 老年代占了三分之二
- 年轻代中Eden占了80%
- Survivor区 占了20%
new出来的对象放在Eden中,一旦Eden被放满了之后 执行引擎就会触发执行引擎垃圾收集的引擎去做垃圾收集, 收集的对象都是无效的对象,是没有被引用的对象
没有被引用的对象:当一个线程执行完后,可是进程还没有退出。堆中的那些被这个线程被new出来的对象没有指针被指向它们的时候,它们就游离了,minor gc 就会清除这些
如果一个对象被minor gc 清除后,它就会被从Eden 中 调到Survivor区中的 From中,然后对象中有一个对象年龄(分代年龄)就会+1,这个分代年龄 存储在对象头中
如果Survivor区被放满, 也会触发 minor gc 去回收对象,如果某些对象还是有引用就会被 从 From 调到 To 区域 , 如果To 满了 也会触发minor gc ,如果To 区域中的对象 还有被引用 将又被调到 From区域中 (这里面是有依次循环)
每经历一次minor gc 分代年龄就会 +1,当一个对象 的年龄到达 15 了 ,就会被调到老年代中
老年代中有哪些东西 比如 :数据库连接池,静态变量
当老年代满了之后 就会触发 full gc:会对老年代中的对象做垃圾回收,可是如果都有用的话,那就只能报错了, full gc 执行的时候会 STW stop the world
为什么双十一的时候有时候卡死,就是因为有可能在做 full gc