【JVM】类的生命周期【转+整理】

参考如下三篇并整理。

1.Java类加载机制详解

2.深入理解Java:类加载机制及反射

3.jvm系列(一):java类的加载机制

 

 

类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段。

1.加载---2.验证---3.准备---3.解析---5.初始化---6.使用---7.卸载

     |________连接________| 

|______________类的加载过程_____________|

|______________________类的生命周期_______________________|

 

其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。

在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。

另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。


 

【1.加载(装载)】

在装载阶段,虚拟机需要完成以下3件事情
(1) 通过一个类的全限定名来获取定义此类的二进制字节流。
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3) 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
虚拟机规范中并没有准确说明二进制字节流应该从哪里获取以及怎样获取,这里可以通过定义自己的类加载器去控制字节流的获取方式。

 

这里第1条中的二进制字节流并不只是单纯地从Class文件中获取,比如它还可以从Jar包中获取、从网络中获取(最典型的应用便Applet)、由其他文件生成(JSP应用)等。

相对于类加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。

 

 

【2.验证(校验、检查)】

  虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统奔溃。

 

  1.文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  2.元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  3.字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  4.符号引用验证:确保解析动作能正确执行。
  验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,

  那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

 

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

这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。

1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。

2、这里设置的初始值,通常是指数据类型的‘“零”值。

  public static int value = 123;

  value在准备阶段过后的初始值为0而不是123,而把value赋值的putstatic指令将在初始化阶段才会被执行。

  注意:

  (1)对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值。

  (2)对基本数据类型来说,对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。

  (3)对于同时被static和final修饰的常量,必须在声明的时候就为其显式地赋值,否则编译时不通过;

  (4)只被final修饰的常量则既可以在声明时显式地赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。

  (5)对于引用数据类型reference来说,如数组引用、对象引用等,如果没有对其进行显式地赋值而直接使用,系统都会为其赋予默认的零值,即null。

  (6)如果在数组初始化时没有对数组中的各元素赋值,那么其中的元素将根据对应的数据类型而被赋予默认的零值。

3、static final常量在准备阶段变量value就会被初始化为ConstValue属性所指定的值,将其结果放入了调用它的类的常量池中。

  public static final int value = 3;

  编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。

 

下表列出了Java中所有基本数据类型以及reference类型的默认零值:

 

 

 

【4.解析】————把类中的符号引用转换为直接引用

 

  解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

  符号引用就是一组符号来描述目标,可以是任何字面量。

 

  直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

 

   1、类或接口的解析:判断所要转化成的直接引用是对数组类型,还是普通的对象类型的引用,从而进行不同的解析。
    2、字段解析:对字段进行解析时,会先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,如果有,则查找结束;
如果没有,则会按照继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口,还没有,则按照继承关系从上往下递归搜索其父类,直至查找结束,查找流程如下图所示:
  3、类方法解析:对类方法的解析与对字段解析的搜索步骤差不多,只是多了判断该方法所处的是类还是接口的步骤,而且对类方法的匹配搜索,是先搜索父类,再搜索接口。
     4、接口方法解析:与类方法解析步骤类似,知识接口不会有父类,因此,只递归向上搜索父接口就行了。

 

【5.初始化】

  详细见此

   类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下(四大种)六小种:

  【1】在如下三个场景(能生成四个字节码指令的场景),如果类还未初始化,则初始化。

        (4个指令【new、getstatic、putstatic、invokestatic】)

   A.new

      new Test();

   B.读取或设置类的静态变量      

      int b=Test.a;Test.a=b;

   C.调用静态函数

      Test.doSomething();

  【2】反射调用。

      Class.forName(“com.mengdd.Test”);

  【3】子类初始化,要先初始化父类(所有父类)。

  【4】虚拟机启动时,要初始化主类。直接使用java.exe命令来运行某个主类。

 

   只有上述四种情况会触发初始化,也称为对一个类进行主动引用。

   除此以外,有其他方式都不会触发初始化,称为被动引用。

注意:

(1)子类引用父类的静态变量,不会导致子类初始化。

(2)通过数组定义引用类,不会触发此类的初始化

(3)引用常量时,不会触发该类的初始化

举例:

(1)子类引用父类的静态变量,不会导致子类初始化。

public class SupClass
{public static int a = 123;static{System.out.println("supclass init");}
}public class SubClass extends SupClass
{static{System.out.println("subclass init");}
}public class Test
{public static void main(String[] args){System.out.println(SubClass.a);}
}

执行结果:

supclass init
123

(2)通过数组定义引用类,不会触发此类的初始化

public class SupClass
{public static int a = 123;static{System.out.println("supclass init");}
}public class Test
{public static void main(String[] args){SupClass[] spc = new SupClass[10];}
}

执行结果:

 

(3)引用常量时,不会触发该类的初始化

public class ConstClass
{public static final String A=  "MIGU";static{System.out.println("ConstCLass init");}
}public class TestMain
{public static void main(String[] args){System.out.println(ConstClass.A);}
}

执行结果:

MIGU

用final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类。

初始化的步骤

1、如果该类还没有加载和连接,则程序先加载该类并连接。

2、如果该类的直接父类没有加载,则先初始化其直接父类。

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

在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,

依次类推,JVM最先初始化的总是java.lang.Object类。

当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

【6.使用】

 

【7.卸载】

 

  在如下几种情况下,Java虚拟机将结束生命周期

  1.执行了System.exit()方法

  2.程序正常执行结束

  3.程序在执行过程中遇到了异常或错误而异常终止

  4.由于操作系统出现错误而导致Java虚拟机进程终止

 

转载于:https://www.cnblogs.com/CESC4/p/8037858.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571437.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java概念,Java基础概念

1. Java编译程序将Java源程序翻译成JVM可执行代码-Java字节码。这一过程同C/C不同。当C编译器翻译成一个对象代码时,该代码是为在某一特定硬件平台运行而产生的。因此,在编译过程中,编译程序通过查表将所有符合引用转换为特定的内存偏移量。而…

【Excle】如何隐藏数据透视表中的错误值

如下:数据透视表出现错误怎么解决呢步骤方法①单击数据透视表任意单元格→数据透视表工具→分析→选项→勾选“对于错误值显示”→确定方法②右键→数据透视表选项(同样可以修改)转载于:https://www.cnblogs.com/OliverQin/p/8043469.html

vue怎么让接口带上cookie_在Vue中怎么使用cookie 之 vue-cookies

cookie 在工作中比较常用, 可以自行封装一些 添加/删除/获取cookie的方法, 可参考这个在Vue中有个很好用的插件 vue-cookiesgithub地址:https://github.com/cmp-cc/vue-cookies我们具体来看下怎么使用这个插件的使用第一步:安装vue-cookienpm install vu…

php 微信分享链接怎么弄,PHP实现 微信--分享朋友链接

不是些高深知识,但是第一次做,确实费了很多的时间.终于一点一点的扣了出来. 目前已经使用中.解决这个问题,总共碰到了几次BUG,1是生成的签名不对,自己打印出来,在去微信的签名算法页面一一核对.这时候如果对了,还是不成功.那就是需要动态获取URL链接的.最后需要将 函数写在为微…

MySQL中整型和字符串类型指定长度的含义

引入: int(5)和char(5)或者varchar(5)中的数字指的是什么意思?是字节数,还是字符长度?为什么在整型中指定了int(5)却可以输入123456? 答案是后者,不管是整型还是字符串类型,后面跟的数字都是字符…

php网站开发项目实战,PHP动态网站开发项目实战

任务1 分析网站需求11.1 知识准备11.1.1 功能结构图11.1.2 用例图21.2 任务实现51.2.1 花公子蜂蜜网站项目功能结构分析51.2.2 花公子蜂蜜网站项目用例分析61.3 经验传递71.4 知识拓展8任务2 设计网站前台版面92.1 知识准备92.1.1 网站版面设计流程92.1.2 网站版面设计原则102.…

repo同步代码_工欲善其事,必先利其器:repo 介绍

介绍此repo非彼repo。这里的repo,是指谷歌公司的一款小工具,名字就叫repo(我承认,这不是一个好名字,Google里面怎么搜都搜不到它的真身)。解决的问题有时候,我们需要在一台电脑上克隆很多个代码仓库,编译它…

洛谷 P1754 球迷购票问题

P1754 球迷购票问题 题目背景 盛况空前的足球赛即将举行。球赛门票售票处排起了球迷购票长龙。 按售票处规定,每位购票者限购一张门票,且每张票售价为50元。在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值100元的钱币。假设…

php date函数实现,PHP date() 函数可实现的功能列表

date() 函数格式化本地日期和时间,并返回已格式化的日期字符串。date(format,timestamp);format 参数为必填,格式为何种格式timestamp 可选参数。规定整数的 Unix 时间戳。默认是当前的本地时间(time())。format参数如下:d - 一个月中的第几天…

ddd 企业应用架构模式_灵魂拷问:用了DDD分包就是落地了领域驱动设计吗?谈谈DDD本质...

学习DDD的时候,作为开发,我们更关心它在技术层面的东西,尤其体现在DDD的分包方式、编码技巧等方面。自然的,我们不禁发问,用了DDD的分包,就是实践落地了DDD了么?不卖关子,直接说答案…

java常见编码

摘自:http://www.cnblogs.com/yaya-yaya/p/5768616.html红色 主要点  灰色 内容 绿色 知识点 橘色 补充内容几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要…

准确率 召回率_机器学习中F值(F-Measure)、准确率(Precision)、召回率(Recall)

在机器学习、数据挖掘、推荐系统完成建模之后,需要对模型的效果做评价。业内目前常常采用的评价指标有准确率(Precision)、召回率(Recall)、F值(F-Measure)等,下图是不同机器学习算法的评价指标。下文讲对其中某些指标做简要介绍。本文针对二元分类器&am…

php 前置操作方法,前置操作-THINKPHP 5.0 手册最新版

前置操作可以为某个或者某些操作指定前置执行的操作方法,设置 beforeActionList属性可以指定某个方法为其他方法的前置操作,数组键名为需要调用的前置方法名,无值的话为当前控制器下所有方法的前置方法。[except > 方法名,方法名]表示这些…

Saving James Bond - Easy Version 原创 2017年11月23日 13:07:33

06-图2 Saving James Bond - Easy Version(25 分) This time let us consider the situation in the movie "Live and Let Die" in which James Bond, the worlds most famous spy, was captured by a group of drug dealers. He was sent to …

commit是直接提交到远程吗 svn_xcode 把项目代码提交到远程SVN服务器

环境 xcode 7 Mac airxcode默认支持GIT源码管理工具,但现在想把代码提交到已有到SVN服务器上,步骤如下:1,在safari中打开svn链接地址,信任证书,输入用户名密码 ,登陆成功,可以在浏览…

oracle导入 表 卡住了,oracle数据库怎么导入dmp,只导入数据不导入表结构?

使用方法:Exp parameter_namevalue or Exp parameter_name(value1,value2……)只要输入参数helpy就可以看到所有帮助.EXP常用选项1.FULL,这个用于导出整个数据库,在ROWSN一起使用时,可以导出整个数据库的结构。例如:ex…

【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set

题目描述 给出一棵树,初始每个点都是非必经的。多次改变某个点的必经状态,并询问从任意一个点出发,经过所有必经的点并回到该点的最小路程。 输入 第一行,两个整数N、M,其中M为宝物的变动次数。 接下来的N-1行&#xf…

vue 引入json地图_VUE中通过Echarts引入地图

渲染的方法如下 记得引入echartsimport echarts from echarts-----------------------------------init(dalian){this.$nextTick(()>{var myChart this.$echarts.init(document.getElementById(echartMap));echarts.registerMap(dalian, dalian,{});myChart.setOption({ser…

Django---admin

Django内置admin 1.配置路由 urlpatterns [url(r^admin/, admin.site.urls),] 2.定制admin 在admin.py中只需要讲Mode中的某个类注册,即可在Admin中实现增删改查的功能,如: admin.site.register(models.UserInfo) 但是,这种方式比…

vue 父组件获取接口值传到子组件_vue父组件异步获取数据传给子组件的方法

但是现在问题是父组件的数据是异步获取的,而子组件一开始就会渲染,如果此时没有传入数据,而子组件又要用到数据中的length属性时就会报错:怎么办呢?最简单的办法就是让子组件条件渲染,当有数据的时候才渲染…