虚拟机可分为:系统虚拟机和程序虚拟机
系统虚拟机:系统虚拟机是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台。例如:Visual Box、VMware 就属于系统虚拟机。
程序虚拟机:程序虚拟机是专门执行单个计算机程序的虚拟机。例如:Java 虚拟机。
Java 虚拟机是一台执行 Java 字节码的虚拟计算机,它拥有独立的运行机制,其运行的 Java 字节码也未必由 Java 语言编译而成。意思是任何语言经过编译后,只要生成的是 .class 文件,就会被 JVM 解析执行。
Java 虚拟机的特点:一次编译,到处运行,自动内存管理,自动垃圾回收。
一次编译,到处运行:.java 文件被编译成 .class 文件后,既可以在 Windows 操作系统上运行,也可以在 Linux 操作系统上运行,还可以在 Mac 操作系统上运行,只要它们的系统上安装了对应版本的虚拟机。体现了 JVM 的跨平台性。
二、类加载过程类的加载过程就是把 .java 文件编译后生成的 .class 文件加载到 JVM 的过程。
x.java 通过 javac 命令编译后生成 x.class 文件,x.class 文件通过类加载器(ClassLoader)加载到 Java 虚拟机。加载的过程又分为 Loading、linking、Initialization 的过程。
Loading:加载,将 .class 文件从磁盘读取到内存,并在内存中构建出 Java 类的原型——类模板对象。
在加载类时,Java 虚拟机必须完成以下 3 件事情:
通过类的全名,获取类的二进制数据流。解析类的二进制数据流为方法区内的数据结构(Java 类模型)在堆中创建 java.lang.class 类的实例,表示该类型,作为方法区这个类的各种数据的访问入口。
linking:链接
Verification:验证,对 .class 文件的格式进行校验,确保加载进来的 .class 文件的安全性。验证主要分为格式验证、语义验证、字节码验证、符号引用验证。格式验证会和加载阶段一起执行,格式验证通过之后,类加载器才会成功将类的二进制数据信息加载到方法区中,接下来在方法区中进行语义验证、字节码验证、符号引用验证。Preparation:准备,给类的静态变量分配内存,并赋默认值。(不包含 final 修饰的静态变量,因为 final 修饰的变量在编译的时候就被会分配)Resolution:解析,将常量池内的符号引用转换为直接引用。
Initialization:初始化,为静态变量赋初始值。
启动类加载器(Bootstrap ClassLoader,也叫引导类加载器):负责加载 JRE 的核心类库,如 JRE 目标下的 jre/lib/rt.jar、chsrsets.jar、resources. jar等。启动类加载器是由 C/C++ 语言实现的。所以调用它的 getClassLoader() 方法返回 null。
扩展类加载器(Extension ClassLoader):负责加载 JRE 扩展目录 ext 中的 jar 类包。
应用程序加载器(Application ClassLoader,也叫系统类加载器):负责加载 ClassPath 路径下的类包。
自定义类加载器(User ClassLoader):我们理解的用户自定义类加载器,是用户自己定义的,实际上官方对自定义类加载器的定义是:所有派生于抽象类 ClassLoader 的类加载器都划分为自定义类加载器。也就是说:所有直接或间接继承 ClassLoader 的类都叫自定义类加载器,Ext ClassLoader 和 App ClassLoader 也是间接继承了 ClassLoader,他们也算是自定义类加载器。
3.2 双亲委派机制如果一个类加载器收到了类加载请求,它不会自己先去加载,而是向上委托,让父类加载器去加载,一直委托到 Bootstrap ClassLoader,如果 Bootstrap ClassLoader 能加载则加载这个类,如果不能加载则让子类加载器去加载,如果所有的子类加载器都不能加载这个类,则会抛出 ClassNotFound 异常。
为什么要搞双亲委派机制?
避免类的重复加载保护程序安全,防止核心 API 被修改
如果没有双亲委派机制,我可以自己写一个 java.lang.String 类覆盖 Oracle 的 String,由于用户输入的密码大部分都是 String 类型,所以我就可以通过自己写的 String 来获取用户的密码。
3.3 沙箱安全机制Java 安全模型的核心就是 Java 沙箱(sandbox)。什么是沙箱?沙箱是一个限制程序运行的环境。沙箱安全机制的作用:
限制程序的运行环境,它将代码归入保护域,不同的保护域有不一样的权限,这样就对代码进行了有效隔离。限制代码对本地系统资源进行访问,防止对本地系统造成破环。保护 Java 原生的 JDK 代码。
沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问。通过这样的措施来保证对代码的有限隔离,防止对本地系统造成破坏。
沙箱主要限制系统资源访问,那系统资源包括什么? CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
所有的 Java 程序运行都可以指定沙箱,可以定制安全策略。JDK1.6时期,引入了域(Domain)的概念。虚拟机会把所有代码加载到不同的系统域和应用域。系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域(ProtectedDomain),对应不一样的权限(Permission)。存在于不同域中的类文件就具有了当前域的全部权限。
3.4 其他JVM 判断两个 class 对象是否为同一个类的两个必要条件:
类的全限定类名必须一致加载这个类的 ClassLoader (ClassLoader 的实例对象)必须相同
在 JVM 中,即使这两个类对象来源于同一个 Class 文件,被同一个虚拟机所加载,但是加载他们的 ClassLoader 不同,这两个类对象就不相等。比如我自己写一个String,包名为 java.lang.String,我自己写这个 String 是通过 User ClassLoader 加载的,而官方的 String 是通过 Bootstrap ClassLoader 加载器加载的,虽然他们的包名和类名一致,但他们也不是同一个类对象。



