初识JVM(一)

一、.java文件到.class文件

  1. 编译过程
    执行 javac Customer.java生成Customer.class文件
    编译的流程:
    Customer.java → 词法分析器 → tokens流 → 语法分析器 → 语法树/抽象语法树 → 语义分析器 → 注解抽象语法树 → 字节码生成器 → Customer.class文件

  2. Class文件

    cafe babe 0000 0034 0027 0a00 0600 1809 
    0019 001a 0800 1b0a 001c 001d 0700 1e07 
    001f 0100 046e 616d 6501 0012 4c6a 6176 
    612f 6c61 6e67 2f53 7472 696e 673b 0100 
    0361 6765 0100 0149 0100 0761 6464 7265 
    ......
    
    ClassFile { 
    	u4 magic; 
    	u2 minor_version; 
    	u2 major_version; 
    	u2 constant_pool_count; 
    	cp_info constant_pool[constant_pool_count-1]; 
    	u2 access_flags;
    	u2 this_class; 
    	u2 super_class; 
    	u2 interfaces_count; 
    	u2 interfaces[interfaces_count]; 
    	u2 fields_count; 
    	field_info fields[fields_count]; 
    	u2 methods_count; 
    	method_info methods[methods_count]; 
    	u2 attributes_count; 
    	attribute_info attributes[attributes_count]; 
    }
    

    magic:标识一个class文件 cafe babe

    minor_version, major_version:0000 0034 对应10进制的52,代表JDK 8中的一个版本

    constant_pool_count:0027 对应十进制27,代表常量池中27个常量

二、类加载

  1. 装载
    (1)通过类的全限定名查找和导入这个类的二进制字节流
    (2)将这个字节流的静态存储结构转换成运行时方法区的数据结构
    (3)在堆中生成一个这个类的class对象,作为访问方法区数据的入口(堆中,类会定义class pointer指向元数据区)

  2. 链接
    (1)验证
    文件格式的正确性
    元数据的正确性
    字节码的正确性
    符号引用的正确性
    (2)预准备
    给类的静态变量分配内存并赋初始值
    (3)解析
    将类中符号引用解析为直接引用

  3. 初始化
    将类的静态变量、静态代码块初始化

在这里插入图片描述

三、类加载器ClassLoader

  1. 在类加载的第一步装载类时候,通过类的全限定名将class文件加载成二进制字节流

  2. Java定义了四种类加载器
    (1)Bootstrap ClassLoader: 加载 J A V A H O M E / j r e / l i b / r t . j a r 或 者 X b o o t c l a s s o a t h 指 定 的 j a r , C + + 实 现 , 不 是 C l a s s L o a d e r 的 子 类 ( 2 ) E x t e n s i o n C l a s s L o a d e r : 加 载 JAVA_HOME/jre/lib/rt.jar 或者 Xbootclassoath 指定的jar,C++实现,不是ClassLoader的子类 (2)Extension ClassLoader:加载 JAVAHOME/jre/lib/rt.jarXbootclassoathjarC++ClassLoader(2)ExtensionClassLoaderJAVA_HOME/jre/lib/*.jar 扩展功能的jar 或者 -Djava.ext.dirs指定目录下的jar
    (3)Application ClassLoader:加载classpath下的jar 或者 -Djava.class.path目录下的jar和类文件
    (4)Customer ClassLoader:用户根据需求自定义加载器继承ClassLoader,tomcat和jboss根据j2ee规范自定义类加载器

  3. 加载规范
    由顶层向下加载,只要父类加载过就不会再加载
    在这里插入图片描述
    双亲委派机制
    定义:如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把
    这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就
    成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
    优势:Java类随着加载它的类加载器一起具备了一种带有优先级的层次关系。比如,Java中的
    Object类,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型
    最顶端的启动类加载器进行加载,因此Object在各种类加载环境中都是同一个类。如果不采用
    双亲委派模型,那么由各个类加载器自己取加载的话,那么系统中会存在多种不同的Object
    类。
    破坏:
    1.可以继承ClassLoader类,然后重写其中的loadClass方法
    2.使用线程上下文类加载器;

四、运行时数据区

  1. 方法区(Method Area)
    方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚 拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规 范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应 该是与Java堆区分开来。jdk1.8后将方法区(Perm Space永久代)换成(MetaData Space元数据区)

  2. 运行时常量池(runtime constant pool)
    运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版 本、字段、方法、接口等描述信息外,还有一项信息是字符串常量池(Constant Pool Table),用于 存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常 量池中存放。jdk1.7之前字符串常量池存放在方法区中,之后存放在堆中 ; 运行时常量池一直存放在方法区中,关于new String(“hello”)会创建几个对象的问题参考运行时常量池

  3. 堆(heap)
    对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。 Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就 是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描 述是:所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展与逃逸分析技 术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都 分配在堆上也渐渐变得不是那么“绝对”了。

  4. Java虚拟机栈(Java Virtual Machine Stacks)
    Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的 生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时 都会创建一个栈帧(Stack Frame)用于存储局部变量表操作数栈动态链接方法出口 等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出 栈的过程。

  5. 程序计数器(The pc Register)
    程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线 程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能 会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选 取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需 要依赖这个计数器来完成。为了线程切换能恢复到正确的执行位置,程序计数器是线程私有的,每个线程互独立、互不干扰。

    (1)如果线程正在执行Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址;
    (2)如果正在执行的是Native方法,则这个计数器为空。

  6. 本地方法栈(Native Method Stacks)
    本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间 的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚 拟机使用到的Native方法服务。在虚拟机规范中对本地方法栈中方法使用的语言、使用方式 与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如 Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法 栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值