一文读懂Jvm类加载机制

前言

一个月没更新了,这个月发生了太多的事情,导致更新的频率大大降低,不管怎样收拾心情,技术的研究不能落下!

jvm作为每个java程序猿必须了解的知识,博主推荐一本书《深入理解Java虚拟机》,以前博主在学校的时候看过几遍,每一次看都有新的理解。加上工作了也有一年多的时间了,有必要好好总结一番~

什么是jvm
平常我们编写代码都是编写的.java文件,怎么部署到机器上运行呢?通过打jar包或者war包,然后部署运行。

如果看过jar包的内容那么就能知道,我们写的.java文件全部被编译成了.class文件。

这里发生了很重要的一个步骤——编译:将我们写的程序翻译成能被jvm读懂的文件格式。

值得注意的是,每一个类都会被编译成一个.class文件,包括内部类等。也就是说每一个.class文件都只对应我们代码中的一个类。

类的生命周期

类被加载到jvm虚拟机内存开始,到卸载出内存为止,他的生命周期可以分为:加载->验证->准备->解析->初始化->使用->卸载。

下面我们来对此一一说明:

加载

当生成一个jar包以后,我们编写的程序就全部编编译成了jvm能读懂的.class格式。此时就需要加载了,将我们的编译好的.class文件加载到jvm中。此时就会有一个“类加载器”的概念。如下图。

接下来一个问题,类加载器何时会将一个.class加载带jvm?也就是说什么情况下会加载一个类?

一个jar包运行的时候会指定一个main()方法作为入口方法。首先就会将main()方法所在的类加载到jvm,当代码执行遇到new的时候又继续将该对象加载到jvm。

所以总结来说,就是在你的代码中需要用到这个类的时候,就会将其加载到jvm中。

验证

这个不需要理解的太深,很直白的道理,不能什么阿猫阿狗都能被加载到jvm中,要不就乱套了。所以该阶段就是来校验加载进来的.class文件是否符合指定的规则。

有一个很有趣的就是,每个.class文件都很浪漫,因为每一个.class文件都是以8个十六进制的 0×CAFEBABE,翻译过来就是咖啡宝贝。浪漫吧?在验证阶段的第一步就是检查.class文件是否以咖啡宝贝来开头的。

准备

当我们合法的把一个.class文件加载到jvm中后,此时就会进行一些准备工作。

首先为这个类分配内存空间,然后为类变量(被static修饰的变量)赋值一个默认的初始值。但是如果类变量同时被final修饰的话,就不是赋值初始值而是具体的值

用下面两种情况来说明:

public class Student{
  private static int age = 18;
}
//此时就会为age变量分配内存空间并且为其赋值 0 这个初始值。
public class Student{
  private static final int age = 18;
}
//age被final修饰,此时就会为age变量分配内存空间并且为其赋值为 18 。

所以我们的流程图可以更新为

解析
解析阶段就是jvm将常量池的符号引用替换为直接引用。

简单的来说就是我们编写的代码中,当一个变量引用某个对象的时候,这个引用在.class文件中是以符号引用来存储的。在解析阶段就需要将其解析为直接引用。如果有了直接引用,那引用的目标必定已经在内存中存在。

所以我们的流程图可以更新为

初始化
在准备阶段我们已经为加载到jvm的类分配了内存空间并且为类变量赋予了初始值。

而到了初始化阶段,才真正开始执行类中定义的java程序代码。主要有以下步骤:

为类的静态变量赋予正确的初始值。
执行类的静态代码块。
按照顺序自上而下运行类中的变量赋值语句和静态语句,并且只有类或接口被Java程序首次主动使用时才初始化他们。如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。

所以我们的流程图可以更新为

总结

在一个静态方法中我们是不能直接使用非静态变量的。当我们使用静态方法的时候,仅仅是初始化了静态方法所在的类,此时只有静态变量是被赋了值而非静态变量是没有被赋值的。所以在静态方法中是不能直接使用非静态变量的。这是我的理解,如果理解有误,欢迎私信博主或留言哦~

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

(0)

相关推荐

  • JVM虚拟机查找类文件的顺序方法

    JVM查找类文件的顺序: 在doc下使用set classpath=xxx, 如果没有配置classpath环境变量,JVM只在当前目录下查找要运行的类文件. 如果配置了classpath环境,JVM会先在classpath环境变量值的目录中查找要运行的类文件. 值的结尾处如果加上分号,那么JVM在classpath目录下没有找到要指定的类文件,会在当前目录下在查找一次. 值的结尾出如果没有分号,那么JVM在classpath目录下没有找到要指定的类文件,不会在当前目录下查找,即使当前目 录下有

  • JVM核心教程之JVM运行与类加载全过程详解

    为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性.例如: 1.编写一个面向接口的应用程序,可能等到运行时再指定其实现的子类: 2.用户可以自定义一个类加载器,让程序在运行时从网络或其他地方加载一个二进制流作为程序代码的一部分:(这个是Android插件化,动态安装更新apk的基础) 为什么研究类加载全过程? 有助于连接JVM运行过程 更深入了解java动态性(解热部署,动态加载),提高程

  • JVM类加载机制详解

    一.先看看编写出的代码的执行过程: 二.研究类加载机制的意义 从上图可以看出,类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 三.类加载的一般过程 原理:双亲委托模式 1.寻找jre目录,寻找jvm.dll,并初始化JVM: 2.产生一个Bootstrap Loader(启动类加载器): 3.Bootstrap Loader自动加载E

  • 从JVM分析Java的类的加载和卸载机制

    类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构. 加载.class文件的方式: 1.从本地系统中直接加载 2.通过网络下载.class文件 3.从zip,jar等归档文件中加载.class文件 4.从专有数据库中提取.class文件 5.将Java源文件动态编译为.class文件 类的加载的最终产品是位于堆区中的Class对象. Class对象封装了类在

  • 详解JVM类加载机制及类缓存问题的处理方法

    前言 大家应该都知道,当一个Java项目启动的时候,JVM会找到main方法,根据对象之间的调用来对class文件和所引用的jar包中的class文件进行加载(其步骤分为加载.验证.准备.解析.初始化.使用和卸载),方法区中开辟内存来存储类的运行时数据结构(包括静态变量.静态方法.常量池.类结构等),同时在堆中生成相应的Class对象指向方法区中对应的类运行时数据结构. 用最简单的一句话来概括,类加载的过程就是JVM根据所需的class文件的路径,通过IO流的方式来读取class字节码文件,并通

  • 一文读懂Jvm类加载机制

    前言 一个月没更新了,这个月发生了太多的事情,导致更新的频率大大降低,不管怎样收拾心情,技术的研究不能落下! jvm作为每个java程序猿必须了解的知识,博主推荐一本书<深入理解Java虚拟机>,以前博主在学校的时候看过几遍,每一次看都有新的理解.加上工作了也有一年多的时间了,有必要好好总结一番~ 什么是jvm 平常我们编写代码都是编写的.java文件,怎么部署到机器上运行呢?通过打jar包或者war包,然后部署运行. 如果看过jar包的内容那么就能知道,我们写的.java文件全部被编译成了.

  • 一篇文章弄懂JVM类加载机制过程以及原理

    目录 一.做一个小测试 二.类的初始化步骤: 三.看看你写对了没? 四.类的加载过程 五.类加载器的分类 1.启动类加载器(引导类加载器) 2.扩展类加载器 3.应用程序类加载器(系统类加载器) 六.类加载器子系统的作用 七.总结 一.做一个小测试 通过注释,标注出下面两个类中每个方法的执行顺序,并写出studentId的最终值. package com.nezha.javase; public class Person1 { private int personId; public Perso

  • 一文读懂Spring Cloud-Hystrix

    Hystrix概述 Hystrix:断路器,容错管理工具,旨在通过熔断机制控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力. hystrix可以实现降级和熔断: 降级 调用远程服务失败(宕机.500错.超时),可以降级执行当前服务中的一段代码,向客户端返回结果 快速失败 熔断 当访问量过大,出现大量失败,可以做过热保护,断开远程服务不再调用 限流 防止故障传播.雪崩效应 在微服务系统中,服务之间进行依赖,避免有调用其中服务失败,而引起其他服务大范围宕机,造成雪崩效应,hystrix

  • 一文读懂Android Kotlin的数据流

    目录 一.Android分层架构 二.ViewModel + LiveData 2.1 LiveData 特性 观察者的回调永远发生在主线程 仅持有单个且最新数据 自动取消订阅 提供「可读可写」和「仅可读」两种方式 配合 DataBinding 实现「双向绑定」 2.2 LiveData的缺陷 value 可以是 nullable 的 传入正确的 lifecycleOwner 粘性事件 默认不防抖 transformation 工作在主线程 2.3 LiveData 小结 三.Flow 3.1

  • 一文读懂Spring Bean的生命周期

    目录 一.前言 1.1 什么是 Bean 1.2 什么是 Spring Bean 的生命周期 二.Spring Bean 的生命周期 三.Spring Bean 的生命周期的扩展点 3.1 Bean 自身的方法 3.2 容器级的方法(BeanPostProcessor 一系列接口) 3.2.1 InstantiationAwareBeanPostProcessor 源码分析 3.2.2 BeanPostProcessor 源码分析 3.3 工厂后处理器方法(BeanFactoryProcesso

  • JVM类加载机制原理及用法解析

    一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的入口.注意这里不一定非得要从一个 Class 文件获取,这里既 可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将 JSP 文件转换成对应的

  • 一文读懂ava中的Volatile关键字使用

    在本文中,我们会介绍java中的一个关键字volatile. volatile的中文意思是易挥发的,不稳定的.那么在java中使用是什么意思呢? 我们知道,在java中,每个线程都会有个自己的内存空间,我们称之为working memory.这个空间会缓存一些变量的信息,从而提升程序的性能.当执行完某个操作之后,thread会将更新后的变量更新到主缓存中,以供其他线程读写. 因为变量存在working memory和main memory两个地方,那么就有可能出现不一致的情况. 那么我们就可以使

  • 一文读懂JAVA中HttpURLConnection的用法

    针对JDK中的URLConnection连接Servlet的问题,网上有虽然有所涉及,但是只是说明了某一个或几个问题,是以FAQ的方式来解决的,而且比较零散,现在对这个类的使用就本人在项目中的使用经验做如下总结: 1:> URL请求的类别: 分为二类,GET与POST请求.二者的区别在于: a:) get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给servlet, b:) post与get的不同之处在于post的参数不是放在URL字串里面,而是放在http请求的正文内. 2:>

  • 一文读懂c++之static关键字

    一.静态变量 与C语言一样,可以使用static说明自动变量.根据定义的位置不同,分为静态全局变量和静态局部变量. 全局变量是指在所有花括号之外声明的变量,其作用域范围是全局可见的,即在整个项目文件内都有效.使用static修饰的全局变量是静态全局变量,其作用域有所限制,仅在定义该变量的源文件内有效,项目中的其他源文件中不能使用它. 块内定义的变量是局部变量,从定义之处开始到本块结束处为止是局部变量的作用域.使用static修饰的局部变量是静态局部变量,即定义在块中的静态变量.静态局部变量具有局

  • 一文读懂Java Iterator(迭代器)

    Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList和HashSet等集合. Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口. 迭代器 it 的两个基本操作是 next .hasNext 和 remove. 调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态. 调用 it.hasNext() 用于检测集合中是否

随机推荐