深入理解JVM


文章目录

    • 1、JVM前言
    • 2、JVM的位置
    • 3、JVM体系架构图
    • 4、类加载器ClassLoader

1、JVM前言
必须掌握的内容
1、请你谈谈你对JVM的理解? java8 虚拟机有什么更新?
2、什么是OOM,请你说说OOM产生的原因?如何分析?
3、JVM 的常用调优参数有哪些?
4、内存快照抓取,如何分析,命令是什么?
5、堆里面分区:Eden、Survial(from to)、老年区
6、GC垃圾收集算法有那个几个?谈谈利弊?
进阶内容
1、JVM 垃圾回收的时候如何确定垃圾,GC Roots?
2、-X、-XX 参数你用过哪些?
3、你常用的项目,发布后配置过JVM 调优参数吗?
4、引用、强引用、弱引用、虚引用都是什么,请你谈谈?
5、GC垃圾回收器和GC算法的关系?分别有哪些?
6、谈谈默认的垃圾回收器?
7、G1垃圾回收器的特点?
8、OOM 你看过几种?
2、JVM的位置 深入理解JVM
文章图片

3、JVM体系架构图 深入理解JVM
文章图片

  • 一般我们所谓的JVM调优,其实主要是对堆(heap)的调整。
  • 栈、程序计数器、本地方法栈中是不会有垃圾的。
4、类加载器ClassLoader 深入理解JVM
文章图片

类的加载、链接、初始化
  • 加载:查找并加载类的二进制数据
  • 链接:
    (1)验证:保证被加载类的正确性
    (2)准备:给类的静态变量分配内存空间,赋值一个默认的初始值。
    (3)解析:被类中的符号应用替换为直接应用(java编译为class文件时,虚拟机并不知道引用的所在地址,作了个标记“符号引用”。转为真正的引用,找到对应的直接地址)
  • 初始化:给静态变量赋正确的值
public class Test{ public static int a = 1; } // 1、加载编译文件为 .class 文件,通过类加载,加载到JVM// 2、连接 验证(1)保证Class类文件没有问题 准备(2)给int类型分配内存空间,a = 0; 解析(3)符号引用转换为直接引用// 3、初始化 经过这个阶段的解析,把1 赋值给 变量 a;

类加载static
package com.coding.classloader; // JVM 参数: //-XX:+TraceClassLoading // 用于追踪类的加载信息并打印出来 //分析项目启动为什么这么慢,快速定位自己的类有没有被加载! // rt.jar jdk 出厂自带的,最高级别的类加载器要加载的! public class Demo02 { public static void main(String[] args) { System.out.println(MyChild1.str2); // 运行的结果 /** * MyParent1 static * MyChild1 static * hello,str2 */ } }class MyParent1{ public static String str = "hello,world"; static { System.out.println("MyParent1 static"); } }class MyChild1 extends MyParent1{ public static String str2 = "hello,str2"; static { System.out.println("MyChild1 static"); } }

常量final
package com.coding.classloader; // 常量 public class Demo03 { public static void main(String[] args) { System.out.println(MyParent02.str); } }class MyParent02{ public static final String str = "hello world"; static { System.out.println("MyParent02 static"); // 这句话会输出吗? } /** * final 常量在编译阶段的时候 常量池; * 这个代码中将常量放到了 Demo03 的常量池中。之后 Demo03与MyParent02 就没有关系了 */ }

package com.coding.classloader; import java.util.UUID; /** * 当一个常量的值并非编译期间可以确定的,那这个值就不会被方法调用类的常量池中! * 程序运行期间的时候,回主动使用常用所在的类 */ public class Demo04 { public static void main(String[] args) { System.out.println(MyParent04.str); } }class MyParent04{public static final String str = UUID.randomUUID().toString(); static { System.out.println("MyParent04 static"); // 这句话会输出吗? }}

ClassLoader分类
1、java虚拟机自带的加载器
  • BootStrap 根加载器 (加载系统的包,JDK 核心库中的类 rt.jar)
  • Ext 扩展类加载器 (加载一些扩展jar包中的类)
  • Sys/App 系统(应用类)加载器 (我们自己编写的类)
2、用户自己定义的加载器
  • ClassLoader,只需要继承这个抽象类即可,自定义自己的类加载器
package com.coding.classloader; // Demo01 public class Demo01 {public static void main(String[] args) { Object o = new Object(); // jdk 自带的 Demo01 demo01 = new Demo01(); // 实例化一个自己定义的对象// null 在这里并不代表没有,只是Java触及不到! System.out.println(o.getClass().getClassLoader()); // null System.out.println(demo01.getClass().getClassLoader()); // AppClassLoader System.out.println(demo01.getClass().getClassLoader().getParent()); // ExtClassLoader System.out.println(demo01.getClass().getClassLoader().getParent().getParent()); // null// 思考:为什么我们刚才自己定义的 java.lang.String 没有生效?// jvm 中有机制可以保护自己的安全; // 双亲委派机制 : 一层一层的让父类去加载,如果顶层的加载器不能加载,然后再向下类推 // Demo01 // AppClassLoader03 // ExtClassLoader02 // BootStrap (最顶层)01java.lang.Stringrt.jar// 双亲委派机制 可以保护java的核心类不会被自己定义的类所替代 } }

双亲委派机制
【深入理解JVM】双亲委派机制 可以保护java的核心类不会被自己定义的类所替代
一层一层的让父类去加载,如果顶层的加载器不能加载,然后再向下类推
// Demo01 // AppClassLoader03 // ExtClassLoader02 // BootStrap (最顶层)01java.lang.Stringrt.jar

    推荐阅读