美文网首页
JVM入门_初探JVM

JVM入门_初探JVM

作者: 啤酒就辣条 | 来源:发表于2018-11-14 21:26 被阅读0次

      开发过java的人员都知道,java是一次编译,多次运行。可以在不同的操作系统上运行代码,用的就是虚拟机jvm,这个东西在jar中,也就是java 的运行环境,所以当你下载jdk的时候,会在官网上找自己需要的版本。

基本原理

      java程序经过一次编译之后,将java代码编译为字节码也就是class文件,然后在不同的操作系统上依靠不同的java虚拟机进行解释,最后再转换为不同平台的机器码,最终得到执行。那么了解了这个基本原理后,我们尝试去做更深的研究,一个普通的java程序它的执行流程到底是怎样的呢?例如我们有一个HelloWorld.java,运行流程如下。

原理图

      首先java文件被编译成class文件,然后找到\jdk1.8.0_101\jre\lib\amd64\jvm.cfg文件,拿到具体的配置信息。接着jdk1.8.0_101\jre\bin\server\jvm.dll就会对jvm进行初始化,所以说jvm.dll是jvm的具体实现。接下来,jvm会获取JNI接口,JNI就是java的本地接口,跟你的硬件、操作系统交互用的,比如说,把文件从硬盘上扔到内存中就是JNI干的。最后,找到main方法,你的程序就可以跑起来了。

      好了,现在知道了jvm的运行原理,下面看一下jvm的内部结构,如下图


jvm内部结构图

      JVM内存空间包含:方法区、java堆、java栈、本地方法栈。

      方法区是各个线程共享的区域,存放类信息、常量、静态变量。

      java堆也是线程共享的区域,我们的类的实例(对象)就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。

      java栈是每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”,而栈帧中包括了方法中的局部变量、用于存放中间状态值的操作栈,这里面有很多细节,我们以后再讲。如果java栈空间不足了,程序会抛出StackOverflowError异常,想一想什么情况下会容易产生这个错误,对,递归,递归如果深度很深,就会执行大量的方法,方法越多java栈的占用空间越大。

      本地方法栈角色和java栈类似,只不过它是用来表示执行本地方法的,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。

      PC寄存器,说到这里我们的类已经加载了,实例对象、方法、静态变量都去了自己改去的地方,那么问题来了,程序该怎么执行,哪个方法先执行,哪个方法后执行,这些指令执行的顺序就是PC寄存器在管,它的作用就是控制程序指令的执行顺序。

      执行引擎当然就是根据PC寄存器调配的指令顺序,依次执行程序指令。

线程通讯

      上节我们知道了jvm运行原理和内部结构,现在看下内部运行模型,线程通信。

线程通讯

      线程1(在栈中)将数据写给主内存(堆),然后线程2再从主内存中读到信息。主内存与工作内存的交互,则需要Java内存模型(JMM)来管理器。当然为了信息的实时更新,java中提供了volatile关键词。

指令重排

public void writer() {
    a = 1;
    flag = true;
}

      有个这样的问题,以上这段代码执行顺序是 a=1 先还是 flag=true呢。你可能说我是傻子,但是运行可能是flag = true;先执行哦,这就涉及指令重排的问题。两个赋值语句尽管他们的代码顺序是一前一后,但真正执行时却不一定按照代码顺序执行。你可能会说,有这个指令重排序那不是乱套了吗?我写的程序都不按我的代码流程走,这怎么玩?这个你可以放心,你的程序不会乱套,因为java和CPU、内存之间都有一套严格的指令重排序规则,哪些可以重排,哪些不能重排都有规矩的。这里就不展开说了。

类加载器原理

      还有最后一个问题,字节码文件是怎样装载到JVM中的呢?


类加载器原理

      加载是类装载的第一步,首先通过class文件的路径读取到二进制流,并解析二进制流将里面的元数据(类型、常量等)载入到方法区,在java堆中生成对应的java.lang.Class对象。

      验证的主要目的就是判断class文件的合法性,比如class文件一定是以0xCAFEBABE开头的,另外对版本号也会做验证,例如如果使用java1.8编译后的class文件要再java1.6虚拟机上运行,因为版本问题就会验证不通过。

      准备过程就是分配内存,给类的一些字段设置初始值,例如:public static int v=1;这段代码在准备阶段v的值就会被初始化为0,只有到后面类初始化阶段时才会被设置为1。但是对于static final(常量),在准备阶段就会被设置成指定的值,例如:public static final int v=1;这段代码在准备阶段v的值就是1。

      解析过程就是将符号引用替换为直接引用,例如某个类继承java.lang.object,原来的符号引用记录的是“java.lang.object”这个符号,凭借这个符号并不能找到java.lang.object这个对象在哪里?而直接引用就是要找到java.lang.object所在的内存地址,建立直接引用关系,这样就方便查询到具体对象。

      初始化过程,主要包括执行类构造方法、static变量赋值语句,staic{}语句块,需要注意的是如果一个子类进行初始化,那么它会事先初始化其父类,保证父类在子类之前被初始化。所以其实在java中初始化一个类,那么必然是先初始化java.lang.Object,因为所有的java类都继承自java.lang.Object。

      类加载器ClassLoader,它是一个抽象类,ClassLoader的具体实例负责把java字节码读取到JVM当中,ClassLoader还可以定制以满足不同字节码流的加载方式,比如从网络加载、从文件加载。ClassLoader的负责整个类装载流程中的“加载”阶段。

相关文章

  • JVM入门_初探JVM

    开发过java的人员都知道,java是一次编译,多次运行。可以在不同的操作系统上运行代码,用的就是虚拟机jvm,这...

  • JVM介绍系列文章

    知晓JVM系列(一):对JVM总览知晓JVM系列(二):JVM内存管理机制与优化初探知晓JVM系列(三) :常用的...

  • JVM内存模型(jvm 入门篇)

    概述 jvm 入门篇,想要学习jvm,必须先得了解JVM内存模型,JVM内存模型,JVM内存模型,JVM内存模型,...

  • 1-JavaBasisBegin

    Java入门 JDK && JRE && JVM JVM(Java Virtual Machine ):Java虚...

  • 九神带你入门JVM(上)

    概述 本篇较长,九神带你从0入门JVM,全文包括包括JVM的分类、JVM垃圾回收综述、JVM的内存模型(Java ...

  • idea中设置JVM参数,简单理解JVM常见参数,JVM调优

    idea中设置JVM参数,简单理解JVM常见参数,JVM调优简单入门 前面学习了JVM的内存分布,今天就来验证下。...

  • 初探JVM

    1、JVM内存模型 各个模块的作用 基本概念 1、堆和栈的区别博客地址 2、Java内存模型分析:虚拟机栈和本地方...

  • 万字长文把[JVM]从头到尾讲一遍

    第一篇:[JVM入门指南01]内存区域与溢出异常——主要介绍JVM的运行时数据区第二篇:[JVM入门指南02]GC...

  • JVM系列之 _call_stub_entry初始化

    在上文JVM系列之函数调用入门已经简单介绍了JVM是如何调用方法的:JVM先调用call_stub()方法将_ca...

  • JVM入门

    Java虚拟机内存包括: 程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池、直接内存。 ...

网友评论

      本文标题:JVM入门_初探JVM

      本文链接:https://www.haomeiwen.com/subject/vvjsfqtx.html