JVM性能优化

一、类的加载机制

  1. 装载(load)
    通过类的全限定名,获取定义此类的二进制字节流,将字节流代表的静态存储结构转化方法区运行时数据结构,并在堆内存中生成一个代表整个类的java.lang.Class。
  2. 链接
    验证:保证加载类的正确性。
    准备:为类的静态变量分配内存,并初始化为默认值。
    解析:将类的符号引用转化为直接引用。
  3. 初始化
    对类的静态变量,静态代码块进行真正初始化

二、类的生命周期

装载
链接
初始化
使用
卸载

三、关于java.lang.Class

Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。Class类对象就是封装了一个类的类型信息,可以通过该对象操作其对应的类,即反射机制。

四、双亲委派机制

类的加载器在收到类的加载请求时,首先不会自己加载这个类,而是将请求委托给父类去加载。在父类无法加载时才会,自己加载这个类。

检查某个类是否已经加载,顺序是自底向上
加载类的,顺序是自上而下

1、Java类的加载器

  • Bootstrap ClassLoader:启动类加载器,负责加载Java核心类,JAVA_HOME中 jre/lib/rt.jar中所有class。
  • Extension ClassLoader:扩展加载器,负责加载扩展功能jar,JAVA_HOME中 jre/lib中的所有jar。
  • App ClassLoader: 应用类加载器,负责加载classpath中的所有类和jar。
  • Custom ClassLoader 自定义加载器,通过java.lang.ClassLoader子类,自定义加载class。

类加载器图解JVM性能优化

2、 如何破坏双亲委派原则

  • 自定义类加载器,重写loadClass方法;
  • 使用线程上下文类加载器;
    线程上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,他将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。

五、运行时数据区

1、内存模型图解

JVM性能优化

2、内存模型理解

方法区

  • 线程共享,在JVM启动时创建
  • 存储类信息(版本、字段、方法、接口)、静态变量、常量、即时编译器编译后的代码等数据
  • 是堆内存的一个逻辑部分,非堆
  • OMM异常
  • 运行时常量池(Run-Time Constant Pool):存储class文件的编译时期产生字面量和符号引用

  • 线程共享,在JVM启动时创建
  • 存储对象的实例,数组

虚拟机栈

  • 线程独享,存储线程中方法的调用状态,一个线程对应一个虚拟机栈
  • 每一个方法对应该栈中的一个栈帧
  • 调用方法,就会向虚拟中压入一个栈帧,执行完一个方法就会从栈中弹出该栈帧

程序计数器

  • 线程独享,用于保存线程中方法的执行状态
  • 执行Java方法,计数器保存的是该方法对应的虚拟机字节码指令的地址
  • 执行Native方法,计数器为空

本地方法栈

  • 线程独享
  • 保存的是本地方法的执行状态

3、栈和栈帧的理解

每个栈帧,对应一个方法,理解为这个栈帧的运行空间。
栈帧:局部变量表、操作数栈、动态链接、方法返回地址

  • 局部变量表:方法的局部变量、参数。局部变量表的变量不可直接使用,需要压至操作数栈中使用
  • 操作数栈:压栈 出栈方式操作数
  • 动态链接:指向运行时常量池中的该栈帧所属方法的引用
  • 方法返回地址:退出方法的两种方式,一遇到返回指令,二遇到异常,且在该方法中未处理。

4、结合内存看对象的创建过程

堆内存模型
JVM性能优化

  1. 新对象申请内存空间
  2. 判断Eden区空间是否充足,充足,直接创建对象。
  3. Eden区空间不足,触发MinorGC,再次判断Eden区空间是否充足,充足,直接创建对象。
  4. Eden区空间仍然不足,判断Survivor空间是否充足,充足,复制部分Eden区存活对象至Survivor区,然后创建对象。
  5. Survivor空间不充足,则判断Old区空间是否充足,充足,复制部分Survivor区存活对象至Old区,然后创建对象。
  6. Old区空间不充足,则触发一次MajorGC,伴随着触发一次MinorGC,等同于触发一次FullGC。
  7. 若空间仍不足则抛出OOM异常。

JVM性能优化