深入理解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_第1张图片

3、JVM体系架构图

深入理解JVM_第2张图片

  • 一般我们所谓的JVM调优,其实主要是对堆(heap)的调整。
  • 栈、程序计数器、本地方法栈中是不会有垃圾的。

4、类加载器ClassLoader

深入理解JVM_第3张图片

类的加载、链接、初始化

  • 加载:查找并加载类的二进制数据
  • 链接:
    (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
        // AppClassLoader       03
        // ExtClassLoader       02
        // BootStrap (最顶层)   01  java.lang.String  rt.jar

        // 双亲委派机制 可以保护java的核心类不会被自己定义的类所替代
    }
}

双亲委派机制

双亲委派机制 可以保护java的核心类不会被自己定义的类所替代
一层一层的让父类去加载,如果顶层的加载器不能加载,然后再向下类推

// Demo01
// AppClassLoader       03
// ExtClassLoader       02
// BootStrap (最顶层)   01  java.lang.String  rt.jar

你可能感兴趣的:(深入理解JVM)