Java代码经历三个阶段:源代码阶段(Source) -> 类加载阶段(ClassLoader) -> 运行时阶段(Runtime)


      

首先我们来理清一下Java代码整个执行过程, 让我们对其有个整体的认识:

Java源程序(.java)经过Java编译器(javac)以后, 生成一个或多个字节码(.class)文件, JVM将每一条要执行的字节码通过类加载器ClassLoader加载进内存, 再通过字节码校验器的校验, Java解释器翻译成对应的机器码,  最后在操作系统解释运行.

当程序要使用某个时, 如果该还未被加载到内存中, 则系统会通过加载, 连接, 初始化三步来实现对这个进行初始化:

加载就是将class文件读入内存, 并为之创建一个Class对象(任何被使用时系统都会创建且只创建一个Class对象)

  JVM进行类加载阶段需要完成以下三件事情:

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

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

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

  类的加载的最终产品是位于区中的Class对象, Class对象封装了类在方法区内的数据结构, 并且向Java程序员提供了访问方法区内的数据结构的接口

  加载时机

    1. 创建类的实例

    2. 使用类的静态变量或者为静态变量赋值

    3. 调用类的静态方法

    4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

    5. 初始化某个类的子类

    6. 直接使用java命令来运行某个主类

  通俗的说就是只要用到了类的东西类就会加载

  JVM在运行时会产生3个类加载器组成的初始化加载器层次结构

  • Bootstrap ClassLoader 根类加载器

   用C++编写

  也被称为引导类加载器, 负责java核心类的加载 该加载器无法直接获取

  比如System, String等, 在JDK中JRE的lib目录下rt,jar文件中

  • Extension ClassLoader 扩展类加载器

  负责JRE的扩展目录中jar包的加载 jre/lib/ext目录下的jar包或-Djava,ext,dirs指定目录下的jar包装入工作库

  • System ClassLoader 系统类加载器(加载自己写的类以及第三方类库(导入的jar包))

  负责在JVM启动时加载来自java命令的class文件, 以及classpath环境变量所指定的jar包和类路径

连接就是将类的二进制数据合并到JRE 

  连接分为以下三步:

    验证 检查载入Class文件数据的正确性

      • 文件格式检验:检验字节流是否符合Class文件格式的规范, 并且能被当前版本的虚拟机处理
      • 元数据检验:对字节码描述的信息进行语义分析, 以保证其描述的内容符合Java语言规范的要求
      • 字节码检验:通过数据流和控制流分析, 确定程序语义是合法、符合逻辑的
      • 符号引用检验:符号引用检验可以看作是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验

      是否有正确的内部结构(构造器, 方法, 变量, 代码块), 并和其他类协调一致

    准备 该阶段正式为类变量分配内存并设置类变量初始值

      这些变量所使用的内存将在方法区中进行分配, 此时进行内存分配的仅包括类变量, 而不包括实例变量(实例变量将会在对象实例化时随着对象一起分配在Java堆中),

      另外, 在这里分配的静态类变量是将其值定义为默认值, 这里所设置的初始值通常情况下是数据类型默认的零值(如0, 0L, null, false等), 而不是被在Java代码中

      被显式地赋予的值, 正确的赋值将在初始化阶段执行,

    解析 将类的二进制数据中的符号引用替换为直接引用

      比如说类中方法中的运算, 运算中符号a=1 去掉a直接变成1, 这样可以节约很多资源

初始化就是对类的静态变量, 静态代码块执行初始化操作

类初始化阶段是类加载过程的最后一步, 前面的类加载过程中, 除了加载(Loading)阶段用户应用程序可以通过自定义类加载器参与之外, 其余动作完全由虚拟机主导和控制, 到了初始化阶段, 才真正开始执行类中定义的Java程序代码

  初始化为类的静态变量赋予正确的初始值, JVM负责对类进行初始化, 主要对类变量进行初始化, 在Java中对类变量进行初始值设定有两种方式:

    • 声明静态变量(类变量)时指定初始值
    • 使用静态代码块为类变量指定初始值

初始化步骤:

1. 假如这个类还没有被加载和连接, 则程序先加载并连接该类

2. 假如该类的直接父类还没有被初始化, 则先初始化其直接父类

3. 假如类中有初始化语句, 则系统依次执行这些初始化语句

  JVM在堆内存中创建对象, 类的成员变量进入到堆内存中, 赋默认值

最后就是我们熟悉的Runtime运行时阶段

Person p = new Person();
p,study();

执行上述代码会在堆内存创建一个Person类的对象, 并且在栈内存分配一块储存空间存放Person类型的引用变量p, p存放该对象的地址并且指向该对象, 调用p的study方法实际是, 对象通过Person类的字节码对象来访问方法区Person字节码的study方法

 


名词解释 :

Java源程序: 即Java源代码, 用java语言编写的程序

Java类加载器(Java Classloader): 是Java运行时环境(JRE)的一部分, 负责动态加载Java类到JVM的内存空间中

JRE: Java Runtime Environment, Java运行环境,内部包含了一个Java虚拟机以及一些标准类库(Jar包)

JAR包: 通常用于聚合大量的Java类文件、相关的元数据和资源(文本、图片等)文件到一个文件, 以便开发Java平台应用软件或库

JVM: Java Virtual Machine一种能够运行Java字节码(Java bytecode)的虚拟机

类(Class): 类是具有共同属性和行为的对象的集合, 类定义了对象的属性和方法

字节码: 字节码是已经经过编译, 但与特定机器码无关, 需要解释器转译后才能成为机器码的中间代码

Java字节码: 是Java虚拟机执行的一种指令格式

Java编译器: 将Java源文件(.java文件)编译成字节码文件(.class文件, 是特殊的二进制文件, 二进制字节码文件), 这种字节码就是JVM的“机器语言”, javac命令可以简单看成是Java编译器

Java解释器: 是JVM的一部分, Java解释器用来解释执行Java编译器编译后的程序, java命令可以简单看成是Java解释器

运行时类: 加载到内存中的字节码文件对应的类称为运行时类,  此运行时类即为一个Class的实例

Java堆(Heap): 在JVM启动时创建, JVM所管理的内存中最大的一块JVM 中,堆(Heap)是可供各条线程共享的运行时内存区域, 也是供所有类实例和数组对象分配内存的区域,  Java堆是被所有线程所共享的一块内存区域, Java堆是垃圾收集器管理的主要区域

Java栈(Stack): 在函数中定义的基本类型的变量、Java指令代码、对象的引用变量均在函数的栈内存中分配,当超过变量的作用域后,Java 会自动释放掉该变量分配的内存空间

方法区(Non-Heap):  方法区与Java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息(构造方法和接口定义)、常量、静态变量、即时编译器编译后的代码等数据, 运行时常量池存在方法区中

Java代码执行过程概述的更多相关文章

  1. 第一章 Java代码执行流程

    说明:本文主要参考自<分布式Java应用:基础与实践> 1.Java代码执行流程 第一步:*.java-->*.class(编译期) 第二步:从*.class文件将其中的内容加载到内 ...

  2. Java程序执行过程及内存机制

    本讲将介绍Java代码是如何一步步运行起来的,其中涉及的编译器,类加载器,字节码校验器,解释器和JIT编译器在整个过程中是发挥着怎样的作用.此外还会介绍Java程序所占用的内存是被如何管理的:堆.栈和 ...

  3. Java 代码执行流程

    Java 代码执行流程 类加载过程 加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载 类加载时机:代码使用到这个类时 验证阶段 &qu ...

  4. 【Hadoop离线基础总结】通过Java代码执行Shell命令

    通过Java代码执行Shell命令 需求 在实际工作中,总会有些时候需要我们通过java代码通过远程连接去linux服务器上面执行一些shell命令,包括一些集群的状态管理,执行任务,集群的可视化界面 ...

  5. Java编译执行过程

    在刷软件设计师中级考试的题目,判断关于编译系统对某高级语言进行翻译的叙述的对错.记得刚开始学Java的时候自己就觉得自己对程序的执行过程理解的相当的透彻,但是一对答案,我的小心脏就有点受不了了,特此在 ...

  6. java 多线程执行过程

    1.分支线程执行 过程: 2.线程运行的状态:五大状态 线程: 从新建状态  就绪状态   运行状态  挂起(阻塞)状态 死亡状态(结束,销毁) 3. 多线程:在同一个时间执行多个任务的操作,现在的软 ...

  7. 08 java代码块的概述和分类

    08.01_面向对象(代码块的概述和分类) A:代码块概述 在Java中,使用{}括起来的代码被称为代码块. B:代码块分类 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代 ...

  8. Java程序执行过程

    首先,写好Java代码,保存到硬盘中.然后在命令行中输入: javac ClassName.java 此时,这个Java类文件将编译成字节码(.class)文件.如果用Eclipse等IDE开发工具, ...

  9. xxe漏洞检测及代码执行过程

    这两天看了xxe漏洞,写一下自己的理解,xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目録遍历等.首先存在漏洞的web服务一定是存 ...

随机推荐

  1. 注册和登录(关于Cookie)

    前记 我将描述一下登陆和注册之间发生了什么,将场景分为客户端和服务端,服务器是Node.JS,客户端是由JS写的 注册 1.注册请求 这是由客户端发送一个POST请求给服务端,其中包含了用户名和密码 ...

  2. 可决系数R^2和方差膨胀因子VIF

    然而很多时候,被筛选的特征在模型上线的预测效果并不理想,究其原因可能是由于特征筛选的偏差. 但还有一个显著的因素,就是选取特征之间之间可能存在高度的多重共线性,导致模型对测试集预测能力不佳. 为了在筛 ...

  3. python-类对象的遍历操作

    视频教程 https://study.163.com/course/courseLearn.htm?courseId=1005985001#/learn/video?lessonId=10533511 ...

  4. table表格 td设置固定宽度

    table宽度自适应,而且部分TD是固定宽度. 只需要将固定宽设死,留下一列不设置宽度,将table宽度设置为100%. table-layout:fixed 作用不是很清楚 <table wi ...

  5. 【leetcode】All Paths From Source to Target

    题目如下: Given a directed, acyclic graph of N nodes. Find all possible paths from node 0 to node N-1, a ...

  6. zrender的线性渐变

    线性渐变 官方文档是这样写的 实际运用是酱紫的 在把颜色放背景中 小白一枚,路过大神,多多指教.欢迎留下宝贵意见

  7. PHP超大文件上传与下载

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  8. 一、Nginx常见问题

    1.相同server_name多个虚拟主机优先级访问 最先读取哪个配置文件,就访问那个的网页 2.location匹配优先级 相同location,会被后面的覆盖 匹配优先级更高的,找后面的 =    ...

  9. PC端无论页面有没有完全撑开把footer保持在最底部(不用定位)

    最近在写项目,有的页面没有占到一屏,然后footer也就是底部就靠上了,这样很影响美观,于是在网上找了找,下面是我的成果 解决该问题的最好方法是采用CSS3提供的一种先进布局模型 :flexbox,可 ...

  10. E. You Are Given Some Strings...

    E. You Are Given Some Strings... AC自动机 求一个串$t$中包含子串$s_{i}+s_{j}$的个数. 可以正反跑两遍AC自动机 正着跑,表示$s_{i}$结束,反正 ...