JVM类运行机制实现原理解析

1.一段java程序是如何运行起来的呢?

Java源文件,通过编译器,产生.Class字节码文件,字节码文件通过Java虚拟机中的解释器,编译成特定及其上的机器码,那Java虚拟机又是怎样加载java程序并执行起来的呢?

简单来说:通过类加载器加载字节码文件,被分配到JVM的运行时数据区的字节码会被执行引擎执行。

(1)类加载器,加载.class文件

(2)运行数据区:栈区、堆区、PC寄存器、本地方法栈、方法区

(3)执行引擎:执行包在装载类方法中的指令

2. 类加载器

类的加载是指将类的.class文件读入内存,将其放在方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构,并向java程序员提供访问方法区内数据结构的接口。类加载器并不需要等到某个类被首次主动使用时再加载它,JVM允许类加载器在预料某个类将要被使用时就预先加载它。

类的生命周期

类加载过程包括:加载、验证、准备、解析、初始化

(1)加载:查找并加载类的二进制数据。

a. 通过一个类的全限定名来获取其定义的二进制字节流

b. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

c. 在Java堆中生成一个代表这个类的java.lang.Class,作为对方法区中这些数据的访问入口

(2)连接:

a. 验证:确保被加载类的正确性

b. 准备:为类的静态变量分配内存,并将其初始化为默认值

c. 解析:把类中的符号引用转换为直接引用

(3)初始化:为类的静态变量赋予正确的初始值

类加载器

  

启动类加载器:BootstrapClassLoader,负责加载存放在JDK\jre\lib或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库。

扩展类加载器:ExtensionClassLoader,负责加载DK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库。

引用程序类加载器:ApplicationClassLoader,负责加载用户路径ClassPath所指定的类

JVM类加载机制

全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入

父类委托:先让父类加载器驶入加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类

缓存机制:保证所有加载过的类都会被缓存,当需要使用某个类时,先从缓存区寻找该Class,只有缓存区不存在该类时,才会去加载此类。

双亲委派机制

意义:系统类防止内存出出现多分同样的字节码;保证Java程序安全稳定运行

(1)当AppClassLoader去加载一个class时,它首先不会自己去加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。

(2)当ExtClassLoader去加载一个class时,它首先也不会自己去加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。

(3)如果BootStrapClassLoader加载失败,会使用ExtClassLoader来尝试加载。

(4)如果ExtClassLoader加载失败,会使用AppClassLoader来加载

(5)如果AppClassLoader也加载失败,则会爆出异常ClassNotFoundException

3. 运行数据区

(1)虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建。栈里面存着一种叫“栈帧”的东东,每个方法会创建一个栈帧,栈帧中存放局部变量表(基本数据类型和对象饮用)、操作数栈、方法出口等信息,栈的大小可以固定也可以扩展,当栈调用深度大于JVM所允许的范围,会抛出StackOverFlowError。

(2)本地方法栈:主要与虚拟机用到的native方法相关,java程序员不太关心。

(3)PC寄存器:也叫程序计数器。JVM支持多线程运行,每个线程都有自己的程序计数器。若当前执行的是JVM的方法,则该寄存器中保存当前执行指令的地址,若执行native方法,则为空。

(4)堆:堆内存是JVM所有线程共享的部分,虚拟机启动时就已经创建。所有对象和数组都在堆上进行分配。这部分空间可通过GC进行回收,当申请不到空间时会抛出OutOfMemoryError。

(5)方法区:所有线程共享。主要用于存储类的信息,常量池,方法数据,方法代码等。

4. 执行引擎

方法调用会导致栈帧的入栈,会确定调用哪一个方法。

(1)栈帧。程序的执行对应着栈帧的入栈和出栈,栈帧主要包括:局部变量表、操作数栈、动态连接、方法返回地址等。

(2)方法调用。

解析调用:类加载的解析阶段,会将其中一部分符号引用转化为直接引用,这种解析的前提是方法在程序真正运行之前就有一个可确定的调用版本。编译期可确定调用方法的版本:静态方法、私有方法、实例构造器、父类方法。
分派调用:

a. 静态分派:发生在编译阶段。所有依赖于静态类型来定位方法执行版本的分派动作成为静态分派,典型方法是重载。javac编译器根据参数的静态类型决定使用哪个重载版本。

b. 动态分派:运行期根据实际类型确定方法执行版本。与方法重写有密切关系。

c. 单分派和多分派:单分派是根据一个宗量对目标方法进行选择,多分派是根据多于一个宗量对目标方法进行选择。

(3)执行引擎需将字节码转换成可以直接被JVM执行的语言,可通过以下两种方式转换:

a. 解释器:一条一条的读取,解释并且执行字节码指令

b. 即时编译器:执行引擎首先按照解释执行的方式来执行,在合适的时候,即时编译器把整段字节码编译成本地代码。内置了JIT编译器的JVM都会检查方法的执行频率,如果一个方法的执行频率超过一个特定的值的话,那么这个方法就会被编译成本地代码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • IdeaGo启动报错Failed to create JVM的问题解析

    [内容]: 问题情况 出现之前做了什么 出错之前通过这个功能增加了个错误的vm参数:-agent:xxx.jar 怎么办? 百度了一圈,都是让删掉:C盘\用户\用户名\.IntelliJIdea2019.3\config\idea64.exe.vmoptions 然而,我这并没有这个文件.百思不得其解,重装等各种方式都试过还是不能用. 思考之: 1.这明显是一个用户下的配置文件,因此肯定是配置文件使用到了用户级别的,改idea下的配置文件肯定是没用的. 2.明显是因为我修改了VM 参数导致的,网

  • JVM Metaspace内存溢出问题解决方案

    一. 现象 前段时间公司线上环境的一个Java应用因为OOM的异常报警,导致整个服务不可用被拉出集群,本地模拟重现的现象如下: 当时的解决方案是增加metaspace的容量:-XX:MaxMetaspaceSize=500m,从原来默认的256m改为500m,虽然没有再出现oom,但这个只是临时解决方案,通过公司的监控系统观察metaspace的使用情况还是在上升,而且后面随着业务访问量越来越大还是有可能达到阈值. 二. 分析 Metaspace元空间主要是存储类的元数据信息,我们的应用里加载的

  • JVM创建对象及访问定位过程详解

    1.对象的创建 虚拟机接收到new指令时,检查这个指令能否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化.如果都没有,先执行类加载过程. 在类加载通过后,虚拟机为新对象分配内存(把一块确定大小的内存从Java堆中划分出来),内存大小在类加载完成后即可完全确定. 两种分配方式: (1):指针碰撞:假设Java堆中内存是绝对规整的,即使用过的内存在一边,空闲的内存在另外一边,中间放着一个指针作为指示器,通过移动指针实现内存分配. (2):空闲列表:如果Jav

  • 浅析JVM的垃圾回收器

    JVM的GC经过多年的发展,大家对Minor GC.major GC的理解并不完全一致,所以我不打算在本文中使用这个概念.我把GC大概分为一下4类: Young GC:只是负责回收年轻代对象的GC: Old GC:只是负责回收老年代对象的GC: Full GC:回收整个堆的对象,包括年轻代.老年代.持久带: Mixed GC:回收年轻代和部分老年代的GC (G1): 因为笔者目前使用G1还是比较少的,所以本文不打算将G1. 垃圾回收器算法 目前主流垃圾回收器都采用的是可达性分析算法来判断对象是否

  • JVM Client和Server端有什么区别

    java -version 命令大家都用过,大部分就是看下jdk版本或检查下环境变量的设置,但最后一行的信息也挺重要,如下图所示: Server VM表示我们的虚拟机类型,mixed mode表示虚拟机以混合模式工作. 一. 虚拟机 先说下本篇文章的内容都是基于HotSpot虚拟机. 我们熟知的Java虚拟机是一种规范标准,有多种实现,比如HotSpot虚拟机就是JVM的一种实现,也是目前使用范围最广的Java虚拟机.其实HotSpot最早也不是Sun开发的,是他早期收购的一家公司开发的,后来S

  • JVM代码缓存区CodeCache原理及用法解析

    一. CodeCache简介 从字面意思理解就是代码缓存区,它缓存的是JIT(Just in Time)编译器编译的代码,简言之codeCache是存放JIT生成的机器码(native code).当然JNI(Java本地接口)的机器码也放在codeCache里,不过JIT编译生成的native code占主要部分. 大致在JVM中的分布如下: 大家都知道javac编译器,把java代码编译成class字节码,它和JIT编译器的区别是,javac只是前端编译(有的叫前期编译),jvm是通过执行机

  • 解决jmap命令打印JVM堆信息异常的问题

    jmap命令可以打印java进程的JVM堆信息,今天在某台机器上运行该命令查看 19560进程的堆信息 jmap -heap 19560 出现以下异常 Attaching to process ID 19560, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.79-b02 using thread-local object allocation. Paralle

  • java编译器和JVM的区别

    Java虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行.java编译器把java编译成字节码,也就是.class文件,然后JVM给编译成的字节码提供运行环境.java的源代码是无法直接在JVM上运行的. 1.java编译器 Java语言写的源程序通过Java编译器,编译成与平台无关的'字节码程序'(.class文件,也就是0,1二进制程序),然后在OS之上的Java解释器中解释执行. 也相

  • JVM性能调优实现原理及配置

    1.JVM内存模型 总结:可以发现最明显的一个变化是元空间从虚拟机转移到了本地内存.默认情况下,元数据空间大小仅受限于本地内存, 这意味着以后不会因为永久代大小不够而抛出OOM异常了. jdk1.8以前,HotSpot VM将class和类的jar包数据存储在PermGen里, PermGen大小是固定的,而且项目之间无法公用公有的class,所以很容易碰到OOM异常.改成MateSpace后, 各个项目会共享同样的class空间.比如多个项目都引用了apache-common包, 在MateS

  • JVM类运行机制实现原理解析

    1.一段java程序是如何运行起来的呢? Java源文件,通过编译器,产生.Class字节码文件,字节码文件通过Java虚拟机中的解释器,编译成特定及其上的机器码,那Java虚拟机又是怎样加载java程序并执行起来的呢? 简单来说:通过类加载器加载字节码文件,被分配到JVM的运行时数据区的字节码会被执行引擎执行. (1)类加载器,加载.class文件 (2)运行数据区:栈区.堆区.PC寄存器.本地方法栈.方法区 (3)执行引擎:执行包在装载类方法中的指令 2. 类加载器 类的加载是指将类的.cl

  • python垃圾回收机制(GC)原理解析

    这篇文章主要介绍了python垃圾回收机制(GC)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 今天想跟大家分享的是关于python的垃圾回收机制,虽然本人这会对该机制没有很深入的了解, 但是本着热爱分享的原则,还是囫囵吞枣地坐下记录分享吧, 万一分享的过程中开窍了呢.哈哈哈. 首先还是做一下概述吧: 我们都知道, 在做python的语言编程中, 相较于java, c++, 我们似乎很少去考虑到去做垃圾回收,内存释放的工作, 其实是p

  • Python类继承和多态原理解析

    这篇文章主要介绍了python类继承和多态原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 现在属于是老年人的脑子,东西写着写着就忘了,东西记着记着就不知道了.之前学C++的时候就把类.对象这块弄得乱七八糟,现在是因为很想玩python,所以就看看python的类和对象. 就像说的,类有三个特征:封装.继承.多态. 1.封装:类封装了一些方法,可通过一定的规则约定方法进行访问权限. C++中的成员变量有public.private.pto

  • Java JVM虚拟机运行机制

    一:JVM基础概念 JVM(Java虚拟机)一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现.编译虚拟机的指令集与编译微处理器的指令集非常类似.Java虚拟机包括一套字节码指令集.一组寄存器.一个栈.一个垃圾回收堆和一个存储方法域. Java虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行. 下面看下Jvm的体系结构图: 二:解释型语言和编译型语言的联系与区别. 编译型语言是通过

  • Python类反射机制使用实例解析

    这篇文章主要介绍了Python类反射机制使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块寻找指定函数并执行. Python有四个内置函数: 函数 功能 getattr(object, attr[, default]) 获取指定字符串名称的对象属性或方法,如果对象有该属性则返回属性值,如果有该方法则返回该方法的内存地址,如果都没有就报错,如果指定了默认值找不到不会报错会取默认

  • Kubernetes controller manager运行机制源码解析

    目录 Run StartControllers ReplicaSet ReplicaSetController syncReplicaSet Summary Run 确立目标 理解 kube-controller-manager 的运行机制 从主函数找到run函数,代码较长,这里精简了一下 func Run(c *config.CompletedConfig, stopCh <-chan struct{}) error { // configz 模块,在kube-scheduler分析中已经了解

  • PHP的运行机制与原理(底层)

    说到php的运行机制还要先给大家介绍php的模块,PHP总共有三个模块:内核.Zend引擎.以及扩展层:PHP内核用来处理请求.文件流.错误处理等相关操作:Zend引擎(ZE)用以将源文件转换成机器语言,然后在虚拟机上运行它:扩展层是一组函数.类库和流,PHP使用它们来执行一些特定的操作.比如,我们需要mysql扩展来连接MySQL数据库:当ZE执行程序时可能会需要连接若干扩展,这时ZE将控制权交给扩展,等处理完特定任务后再返还: 最后,ZE将程序运行结果返回给PHP内核,它再将结果传送给SAP

  • Springboot错误处理机制实现原理解析

    1.默认的错误机制 默认效果 ①在浏览器中访问不存在的请求时,springboot默认返回一个空白页面 浏览器的请求头 ②客户端访问时,返回json数据 { "timestamp": "2020-03-24T02:49:56.572+0000", "status": 404, "error": "Not Found", "message": "No message availa

  • javascript类继承机制的原理分析

    目前 javascript的实现继承方式并不是通过"extend"关键字来实现的,而是通过 constructor function和prototype属性来实现继承.首先我们创建一个animal 类 js 代码 复制代码 代码如下: var animal = function (){ //这就是constructor function 了 this .name = 'pipi'; this .age = 10; this .height = 0; } //建立一个动物的实例 var

  • Java for each实现机制代码原理解析

    源测试代码如下 public class ForEachTest { public void test4Iterate(Iterable<String> strings) { for (String str : strings) { System.out.println(str); } } public void test4Array(String[] strings) { for (String str : strings) { System.out.println(str); } } }

随机推荐