Java代码执行过程概述
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代码执行过程概述的更多相关文章
- 第一章 Java代码执行流程
说明:本文主要参考自<分布式Java应用:基础与实践> 1.Java代码执行流程 第一步:*.java-->*.class(编译期) 第二步:从*.class文件将其中的内容加载到内 ...
- Java程序执行过程及内存机制
本讲将介绍Java代码是如何一步步运行起来的,其中涉及的编译器,类加载器,字节码校验器,解释器和JIT编译器在整个过程中是发挥着怎样的作用.此外还会介绍Java程序所占用的内存是被如何管理的:堆.栈和 ...
- Java 代码执行流程
Java 代码执行流程 类加载过程 加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载 类加载时机:代码使用到这个类时 验证阶段 &qu ...
- 【Hadoop离线基础总结】通过Java代码执行Shell命令
通过Java代码执行Shell命令 需求 在实际工作中,总会有些时候需要我们通过java代码通过远程连接去linux服务器上面执行一些shell命令,包括一些集群的状态管理,执行任务,集群的可视化界面 ...
- Java编译执行过程
在刷软件设计师中级考试的题目,判断关于编译系统对某高级语言进行翻译的叙述的对错.记得刚开始学Java的时候自己就觉得自己对程序的执行过程理解的相当的透彻,但是一对答案,我的小心脏就有点受不了了,特此在 ...
- java 多线程执行过程
1.分支线程执行 过程: 2.线程运行的状态:五大状态 线程: 从新建状态 就绪状态 运行状态 挂起(阻塞)状态 死亡状态(结束,销毁) 3. 多线程:在同一个时间执行多个任务的操作,现在的软 ...
- 08 java代码块的概述和分类
08.01_面向对象(代码块的概述和分类) A:代码块概述 在Java中,使用{}括起来的代码被称为代码块. B:代码块分类 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代 ...
- Java程序执行过程
首先,写好Java代码,保存到硬盘中.然后在命令行中输入: javac ClassName.java 此时,这个Java类文件将编译成字节码(.class)文件.如果用Eclipse等IDE开发工具, ...
- xxe漏洞检测及代码执行过程
这两天看了xxe漏洞,写一下自己的理解,xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目録遍历等.首先存在漏洞的web服务一定是存 ...
随机推荐
- RestTemplate 超级严重BUG之 restTemplate.getForEntity对于下载文件的地址请求 header不起作用
错误下载:RestTemplate restTemplate=new RestTemplate();HttpHeaders httpHeaders=new HttpHeaders();httpHead ...
- win10系统迁移到新的硬盘
笔记本换个硬盘,但是程序员在开发中需要各种环境配置,不想重装系统,重新系统容易,但是装各种软件和配各种环境就比较麻烦了,所以笔记本加固态硬盘,可以不用重装,直接"系统迁移"到新的硬 ...
- js 将时间戳转为日期格式
最近项目需要在前端将一个13位的时间戳显示成日期格式,在网上查了很多都不符合要求,只有一个是能满足要求的,在这记录一下,说不定以后还用的着. 13位时间戳改为yyyy-MM-dd HH-mm-ss 格 ...
- Internet History, Technology, and Security(week9)——Web Security
Secure Web Connections: Security Public/Private Key - Secure Sockets 凯撒密码容易被破解,后来人们发明了公钥和私钥,由于私钥一定是要 ...
- APK文件结构和安装过程
APK文件结构Android应用是用Java编写的,利用Android SDK编译代码,并且把所有的数据和资源文件打包成一个APK (Android Package)文件,这是一个后缀名为.apk的压 ...
- All-one Matrices
All-one Matrices 单调栈 最大全一矩阵计数 #include<bits/stdc++.h> #define maxn 3005 using namespace std; # ...
- (转)mnist.load_data()出现错误
解决方法:本地导入1.下载mnist.npz文件mnist.npz链接imdb.npz链接2.将上述文件放于合适位置(执行keras程序的python环境中),因为我用的是python虚拟环境,所以我 ...
- QTP 11 补丁大全
原文: http://relevantcodes.com/qtp-11-0-patches/ Patch Link Details Support for Chrome 19 QTPWEB_00102 ...
- Microsoft SQL Server 2008 R2官方中文版(SQL2008下载)
Microsoft SQL Server 2008 R2官方中文版(SQL2008下载) http://www.2cto.com/database/201308/235349.html
- AngleSharp 网络数据采集 -- 使用AngleSharp做html解析
AngleSharp AngleSharp is a .NET library that gives you the ability to parse angle bracket bas ...