在大学几年我最常用的编程语言就是java。众所周知,Java需要运行在jvm虚拟机上。虽然编程常用到jvm。但是我一点也不了解jvm。通过阅读这篇文章使我对jvm有了更加深入的了解。
Jvm不仅可以运行java,还可以运行其他语言。JVM可以使程序“一次编译到处执行”和自动回收。Java文本文件需要先经过JDK的编译器编程称class文件。然后进入JVM中。但是JVM中它并不能够认出使java语言编写的,它只认识class文件。JVM规范严格定义了CLASS文件的格式,有严格的数据结构。作者认为每个CLASS文件类别成一个一个的数据库,里面包含的常量池/类索引/属性表集合就像数据库的表,而且表之间也有关联,常量池则存放着其他表所需要的所有字面量。
作者接着讲了Jvm的加载机制。AVA的则是在命令行执行java classFile,操作系统启动的是java进程,而HelloWorld类只是命令行的入参,在操作系统来看java也就是一个普通的应用进程而已,而这个进程就是JVM的执行形态。JAVA的入口方法是public static void main(String[] args),缺一不可,应该是执行java命令时JVM对该入口方法做了唯一验证,通过了才允许启动JVM进程。JVM是由C/C++语言实现的,那么JVM跟CLASS打交道则需要JNI(Java Native Interface)这座桥梁,当我们在命令行执行java时,由C/C++实现的java应用通过JNI找到了HelloWorld里面符合规范的main方法,然后开始调用。
类加载器的工具把类加载到JVM实例里面。JVM在执行类的入口之前,首先得找到类再然后再把类装到JVM实例里面,也即是JVM进程维护的内存区域内。内置的类加载器有明确的范围限定,也就是只能加载指定路径下的jar包(类文件的集合)。如果只是加载JRE的类,那可玩的花样就少很多,JRE只是提供了底层所需的类,更多的业务需要我们从外部加载类来支持,所以我们需要指定新的规则,以方便我们加载外部路径的类文件。
内置类加载器只加载了最少需要的核心JAVA基础类和环境变量下的类,但是我们应用往往需要依赖第三方中间件来完成额外的业务,那么如何把它们的类加载进来就显得格外重要了。幸好JVM提供了自定义类加载器,可以很方便的完成自定义操作,最终目的也是把外部的类文件加载到JVM内存。通过继承ClassLoader类并且复写findClass和loadClass方法就可以达到自定义获取CLASS文件的目的。
现有的加载器分为内置类加载器和自定义加载器,自定义类加载器可以干出很多黑科技,但是有个基本的雷区就是,不能随便替代JAVA的核心基础类,或者说即是你写了一个跟核心类一模一样的类,JVM也不会使用。
加载过程包括:加载,链接,初始化,使用,卸载。JVM触发类加载器去加载外部的CLASS文件的四种情况:(1)显式字节码指令集(new/getstatic/putstatic/invokestatic):对应的场景就是创建对象或者调用到类文件的静态变量/静态方法/静态代码块。(2)反射:通过对象反射获取类对象时。(3)继承:创建子类触发父类加载(4)入口:包含main方法的类首先被加载。初始化就是把变量的初始值和构造方法的内容初始化到变量的空间里面。使用呼应了我们加载类的触发条件,也即是触发类加载的条件也是类应用的条件,该操作会在初始化完成后进行。JVM有垃圾回收机制。
JVM内存从应用逻辑上可分为如下区域。(1)程序计数器:字节码行号指示器,每个线程需要一个程序计数器(2)虚拟机栈:方法执行时创建栈帧(存储局部变量,操作栈,动态链接,方法出口)编译时期就能确定占用空间大小,线程请求的栈深度超过jvm运行深度时抛StackOverflowError,当jvm栈无法申请到空闲内存时抛OutOfMemoryError,通过-Xss,-Xsx来配置初始内存。(3)本地方法栈:执行本地方法,如操作系统native接口。(4)堆:存放对象的空间,通过-Xmx,-Xms配置堆大小,当堆无法申请到内存时抛OutOfMemoryError(5)方法区:存储类数据,常量,常量池,静态变量,通过MaxPermSize参数配置。(6)对象访问:初始化一个对象,其引用存放于栈帧,对象存放于堆内存,对象包含属性信息和该对象父类、接口等类型数据(该类型数据存储在方法区空间,对象拥有类型数据的地址)
作者从JVM的最小元素类的结构出发,介绍类加载器的工作原理和应用景,思考类加载器存在的意义。进而描述JVM逻辑内存的分布和管理方式,同时列举常用的JVM调优工具和使用方法,最后介绍高级特性JDPA框架和字节码增强技术,实现热替换。从微观到宏观,从静态到动态,从基础到高阶介绍JVM的知识体系。看完jvm我感觉创造出来居民们的人比较伟大,因为jvm从内存,到加载类,要经过很多流程才能将一个程序运行,将结果展示在控制台上。而开发人员只能编写程序,jvm帮助程序员做了许多事。