本文共 2795 字,大约阅读时间需要 9 分钟。
【JVM篇】一、初识JVM
【JVM篇】目录:
01 JDK JRE JVM
- JDK(Java Development Kit): 是针对Java开发程序员的产品,包含了Java运行环境JRE,Java工具和Java基础类库。
- JRE(Java Runtime Environment):运行Java程序所必须的环境的集合,包含JVM标准实现以及Java核心类库。
- JVM(Java Virtual Machine):是整个Java实现跨平台的最核心的部分。所有的Java程序首先会被编译成.class的类文件,这种类文件可以在虚拟机上运行。但解释class文件的时候JVM需要解释所需要的类库lib。
02 Java源文件到JVM的过程
2.1 源码编译到class类文件
源码
编译过程
对上述的Person.java文件进行编译到class类文件。
javac Person.java —> Person.class
class字节码文件
魔数与class文件版本
常量池
访问标志
类索引、父类索引、接口索引
字段表集合
方法表集合
属性表集合
2.2 class类文件加载到JVM虚拟机中
- 装载(Load):查找和导入class文件
- 通过一个类的全限定名获取定义此类的二进制字节流
- 将这个字节流所代表的的静态存储结构转换为方法区的运行时数据结构
- 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
- 链接(Link)
- 验证(Verify):保证被加载类的正确性
- 准备(Prepare):为类的静态变量分配内存,并将其初始化为默认值
- 解析(Resolve):将类中的符号引用转换为直接引用
- 初始化(Initialize):对类的静态变量,静态代码块执行初始化操作
03 重要知识点-类装载器
在装载(Load)阶段,其中第(1)步:通过一个类的全限定名获取定义此类的二进制字节流,需要借助类装载器来完成。
类装载器的分类
- Bootstrap ClassLoader 负责加载$JAVA_HOME中 jre/lib/rt.jar 里所有的class或 Xbootclassoath选项指定的jar包。由C++实现,不是ClassLoader子类。
- Extension ClassLoader 负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中 jre/lib/*.jar 或 -Djava.ext.dirs指定目录下的jar包。
- App ClassLoader 负责加载classpath中指定的jar包及 Djava.class.path 所指定目录下的类和 jar包。
- Custom ClassLoader 通过java.lang.ClassLoader的子类自定义加载class,属于应用程序根据 自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader。
04 重要知识点-运行时数据区(Run-Time Data Areas)
在装载(Load)阶段的(2)(3)步可以发现时运行数据、堆、方法区等名词。
(2)将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构
(3)在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口、
即类文件被类装载器装载进来之后,类中的内容(比如变量、常量、方法、对象等这些数据要有个去处,需存储起来,存储的位置在JVM中有对应的空间)
4.1 方法区(Method Area)
方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
注意:
- 方法区是JVM的一个概念定义,并不是具体的实现。在JDK1.8之后用的元空间来实现的方法区;在JDK1,8之前用的永久代实现的方法区。(此外元空间是使用本地内存Native Memory实现的,也就是它的内存不是在虚拟机内的,不受限与JVM本身分配的内存。此外JDK1.8中JVM把字符串常量池移到了堆内存中。)
- 运行时常量池:方法区还包含了一个运行时常量池用于存放编译时期生成的字面量和符号引用。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
4.2 堆(Heap)
Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域。所有的对象实例以及数组都在堆上分配空间。
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
4.3 虚拟机栈(Java Virtual Machine Stacks)
虚拟机栈是Java方法执行的内存模型。每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个Java线程的运行 状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的,随着线程的创建而创建。 每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。 调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。
注意:
在Java虚拟机规范中,对这个区域规定了两种异常状况:
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
4.4 本地方法栈(Native Method Stack)
本地方法栈与虚拟机栈所发挥的作用是非常相似的,只不过本地方法栈为虚拟机使用到的Native方法服务。
与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
4.5 程序计数器(Program Computer Register)
程序计数器可以看成当前线程所执行的字节码的行号指令器。
由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的适合,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
如果线程正在执行Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址;
如果线程正在执行Native方法,则这个计数器会空。
此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
转载地址:https://codingchaozhang.blog.csdn.net/article/details/111182588 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!