JVM学习笔记一

Java代码执行流程

java代码在执行过程中,通过java编译器编译之后生成相对应的字节码文件,通过jvm加载校验之后进行执行。

jvm架构模型及其特点

jvm基于栈式架构,其特点是

  1. 设计和实现更加单,适用于资源受限的系统;
  2. 使用零地址指令方式,避开了寄存器的分配问题;
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈,指令集更小,编译器容易实现;
  4. 不需要硬件支持,可移植性更好,更好实现跨平台;

jvm生命周期

  1. 启动:通过引导类加载器创建一个初始类来完成启动,这个初始类由虚拟机的具体实现指定(比如自定义类的加载通过系统类加载器实现),当执行一个类需要使用到一些自身以及父类结构或者其他的类结构时,这时就会启动jvm,当jvm启动后,就会调用初始类中的main()方法执行程序。
  2. 运行:当程序执行时jvm也开始运行,程序结束时,jvm也结束运行,执行一个java程序时,真正执行的是jvm的进程。
  3. 退出:程序正常执行结束;程序执行过程中遇到异常或错误而异常结束;操作系统问题导致jvm进程结束;某线程调用Runtime类或者System类的exit方法,或者Runtime类的halt方法,并且java安全管理器允许该操作。

类加载器(ClassLoader)

  1. 类加载器负责从文件系统或者网络中加载class文件,class文件存于本地硬盘,通过二进制流的方式加载到内存中,(class文件可以理解为一个模版,而jvm就是根据这个模版实例化出相对应的实例),class文件在文件开头有特定的文件标识;
  2. 类加载器只负责加载class文件,而class文件能否运行则由执行引擎(Execution Engine)来决定;
  3. 加载的类信息会被加载到jvm,存放于方法区,称为DNA元数据模版,除了类信息外,方法区还存储运行时的常量池信息(可能还包括class文件中常量池部分内存映射的字符串和数字常量);
  4. 类加载器在class文件经过jvm最终成为元数据模版的过程中起到一个传输数据的作用

类加载过程(三阶段)

1-loading阶段:这一阶段是类的初步加载阶段,通过一个类的全类名信息获取定义这个类的二进制字节流,再将这个字节流所代表的静态存储结构转化为方法区(元空间)的运行时数据结构,最终在内存中生成一个代表这个类的java.lang.Class对象做为方法区中这个类的各种数据的访问入口。
2-linking阶段:这一阶段是完成loading阶段的加载之后,对加载的数据进行验证解析的过程,分为三个步骤:

  1. 验证(verify):目的在于确保class文件中的字节流包含信息符合当前虚拟机的要求,保证类加载的正确性,不会危害虚拟机自身安全,主要的验证方式为:文件格式验证,元数据验证,字节码验证,符号引用验证,如果验证失败则报VerifyError终止程序运行。
  2. 准备(prepare):为类变量分配内存并且设置默认初始值。需要注意的是这时并不会为实例变量进行内存分配和初始化,因为类变量会被分配在方法区中,而实例变量是随着对象的创建而被分配到堆空间中;并且使用final修饰的类变量(静态变量)也不会进行内存分配和初始化,因为final修饰的变量在编译时就会被分配,在这个阶段会显式初始化,也就是说准备阶段不会为常量设置默认值,常量的默认值在编译时就已经分配了,在准备阶段会显示初始化,实例变量的初始化过程是当程序中造了对象之后才会去涉及变量初始化
  3. 解析(resolve):解析操作往往会随着jvm执行完初始化之后再执行,这一操作也就是将常量池中的符号引用转换为直接引用的过程。(符号引用就是用一组符号来描述所引用的目标,符号引用格式就是class文件格式中的样子;直接引用就是直接指向目标的指针,相对偏移量或一个间接定位到目标的句柄),而解析操作主要就是针对类或接口,字段,类方法,接口方法,方法类型等。对应常量池中的CONSTANT_Class_info,CONSTANT_Fieldref_info,COMSTANT_Methondref_info 等。

3-initialization阶段:初始化阶段就是执行类构造器方法 < clinit >() 的过程。

  1. 这个方法是javac编译器自动收集类中的所有类变量的赋值操作和静态代码块中的语句合并的,如果类中不含静态属性或者静态代码块,则不会自动生成该方法,而最终的赋值顺序则与静态属性和静态代码块的顺序相同。
  2. 如果该类有父类,则会在子类的该方法执行前已经执行完父类的该方法
  3. 该方法不同于类的构造器方法,类的构造器方法是对于当前类创建实例时的一个初始化。
  4. 虚拟机必须保证一个类的< clinit>() 方法在多线程下被同步加锁,因为该方法初始化后的数据存放在方法区中是会被共享的。

类加载器的分类

启动类加载器(Bootstrap ClassLoader):这个类加载器使用C/C++实现,嵌套在JVM内部,用来加载java的核心库,用于提供JVM自身需要的类,只加载包名为java,javax,sun等开头的类。是扩展类和系统类加载器的父类加载器。
扩展类加载器(Extension ClassLoader):派生与ClassLoader类,从java.ext.dirs系统属性所指定的目录中加载类库,或者JDK安装目录的jre/lib/ext子目录下加载类库,如果用户自定义的jar也在此目录下,扩展类加载器也会加载。
系统类加载器(AppClassLoader):派生于ClassLoader类,父类加载器为扩展类加载器,负责加载环境变量classPath或者系统属性java.class.path指定路径下的类库,是程序中默认的类加载器,java应用的类都由其加载,可通过ClassLoader.getSystemClassLoader()方法获取该类加载器

双亲委派机制

双亲委派机制避免了类重复加载,防止核心API被随意篡改,保护了程序安全
工作原理:如果一个类加载器收到了类加载请求,他并不会自己去加载,而是把这个请求委托给自己的父类加载器去执行,依次向上递归委托,请求最终会到最顶级启动类加载器,(期间如果父类加载器能够完成加载任务,则有父类加载器进行加载)如果启动类加载器拒绝失败,则又由启动类加载器依次向下递归委托,交由子加载器进行加载。

沙箱安全机制

当我们定义一个与javaAPI核心库中同名类时,在类加载过程中,类加载器会优先使用引导类加载器进行加载,而引导类加载器在加载的过程中会先加载jdk自带的文件,而自定义的java文件必然会与jdk自带的有冲突,所以就会报错,这样就保护了java核心源代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值