JVM的位置

JVM运行在操作系统之上,在JVM之下的还有硬件体系,JVM与硬件没有直接交互

JVM的体系结构

java源代码通过javac编译为Class File,字节码文件进入类装载器Class Loader,在通过类装载器进入运行时数据区
运行时数据区中只有方法区和堆会存在垃圾

JVMt体系结构

类加载器

类模板

类是一个模板是抽象的,而对象是实例的具体的
所有同一个类的模板都是相同的

public class Car {
    public int age;

    public static void main(String[] args) {
        Car car = new Car();
        Class<? extends Car> aClass = car.getClass();
        Class<? extends Car> aClass2 = car.getClass();
        Class<? extends Car> aClass3 = car.getClass();
        // always true
        System.out.println(aClass == aClass2);
        // always true
        System.out.println(aClass2 == aClass3);
    }
}

双亲委派机制

public class Car {
    public int age;

    public static void main(String[] args) {
        Car car = new Car();
        Class<? extends Car> aClass = car.getClass();

        ClassLoader classLoader = aClass.getClassLoader();
        // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(classLoader);
        ClassLoader parent = classLoader.getParent();
        // sun.misc.Launcher$ExtClassLoader@1b6d3586
        System.out.println(parent);
        ClassLoader parent2 = parent.getParent();
        // null
        System.out.println(parent2);
    }
}

Car的类加载器的父类加载器是/jre/lib/ext.jar包,属于扩展类加载器
Car的类加载器的父类加载器的父类加载器是/jre/lib/rt.jar包,属于根加载器,JVM底层获取不到,所以为null
双亲委派机制为了确保安全

  1. 双亲委派机制执行流程APP -> EXC -> BOOT
  2. 在应用程序加载器(APP)中寻找
  3. 然后进入扩展加载器(EXC)中寻找
  4. 最终在根加载器中(BOOT)中执行
  5. 所以会在以下示例中出现找不到main方法的错误,因为最终执行的是根加载器中的String,而这个String类中不存在main方法

类加载器收到类加载的请求
将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载,启动类加载器好后检查是否能够加载这个类。
如果能加载就使用当前加载器,否则抛出异常,通知子加载器进行加载
,最终抛出ClassNotFoundException

package java.lang;

public class String {
    public String toString() {
        return "String";
    }

    public static void main(String[] args) {
        /**
         * Exception in thread "main" java.lang.NoSuchMethodException: java.lang.String.main([Ljava.lang.String;)
         * at java.lang.Class.getMethod(Class.java:1786)
         * at com.intellij.rt.execution.application.AppMain.main(AppMain.java:125)
         */
        System.out.println(new String().toString());
    }
}

除非改写JVM内的jar包,无法通过这样的方法制造不安全的问题

沙箱隔离机制

  Java安全模型的核心就是沙箱,沙箱是一个限制程序运行的环境。沙箱机制就是
将Java代码限定在虚拟机特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保
证对代码的有效隔离,防止对本地系统造成破坏。不同级别的沙箱对这些资源访问的限制也可以不一样。
在Java中将执行程序分成本地代码和远程代码两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。
在JDK1.1针对安全机制进行了改进允许代码对本地资源的访问权限,JDK1.2增加了代码签名。当前使用的安全机制,则引入了域的概念,会把代码加载到不同的域,不同的域拥有不同的权限。

字节码校验器
确保Java类文件遵循Java语言规范。但并不是所有类都会经过字节码校验,比如核心类

类装载器
其中类装载器对Java沙箱起作用的3个方面

  1. 防止恶意代码去干涉善意代码
  2. 守护被信任的类库的边界
  3. 将代码归于保护域,确定类代码可以进行哪些操作

Native

带了native关键字的方法不需要实现,会进入本地方法栈调用本地方法接口(Java Native Interface),扩展Java的使用
它在内存区域专门开辟了一块标记区域登记native方法
在最终执行的时候,加载本地方法库中的方法通过JNI

PC寄存器

每个线程都有一个程序计数器,是线程私有的,是一个指针, 指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计

...未完待续