android支持java14吗,Android进阶(14)| Java虚拟机

0ea1f60ba518

本节目录

一.Java虚拟机概述

定义:Java虚拟机(JVM)是Java程序运行的标准环境。可以把Java虚拟机看作一个抽象的计算机,它有各种指令集和各种运行时的数据区域。虽然是叫做Java虚拟机,但是在它之上运行的语言不仅有Java,还包括Kotlin、Groovy等JVM系语言。

1.Java虚拟机家族

HotSpot VM

是Oracle JDK和openJDK中自带的虚拟机,是最主流和使用范围最广的Java虚拟机。

J9 VM

由IBM开发的虚拟机。

Zing VM

以HotSpot VM为基础进行改进的虚拟机。

2.Java虚拟机执行流程

Java虚拟机执行流程分为两大部分,分别是编译时环境和运行时环境,当一个Java程序经过Java编译器编译之后,会产生一个Class文件,这个Class文件会由Java虚拟机来进行处理。

Java虚拟机只与特定的二进制文件Class有关,也就是说无论任何语言,只要能够生成Class文件,就可以被Java虚拟机识别并执行。

二.Java虚拟机结构

0ea1f60ba518

Java虚拟机结构

Java虚拟机结构包括:运行时数据区域、执行引擎、本地库接口和本地方法库,而类加载子系统并不属于Java虚拟机的内部结构。

1.Class文件格式

Java文件被编译后生成了Class文件,而这种二进制文件不依赖于特定的硬件和操作系统。每一个Class文件都对应着唯一的类或者接口的定义信息,但是类或者接口并不一定定义在文件中。Class文件格式如下:

0ea1f60ba518

Class文件格式

Class文件的基本数据类型如下所示:

u1:1字节,无符号类型

u2:2字节,无符号类型

u4:4字节,无符号类型

u8:8字节,无符号类型

2.类的生命周期

定义:一个Java文件被加载到Java虚拟机内存中到从内存中卸载的过程称为类的生命周期。

生命周期阶段:

(1) 加载:查找并由类加载子系统来加载Class文件。

(2) 链接:包括验证、准备和解析。

验证:确保被导入类型的正确性

准备:为类的静态字段分配字段,并用默认值初始化这些字段

解析虚拟机将常量池内的符号引用替换为直接引用

(3) 初始化:将类变量初始化为正确的初始值。

3.类加载子系统

定义:类加载子系统通过多种类加载器来查找和加载Class文件到Java虚拟机中,Java虚拟机中有两种类加载器:系统加载器和自定义加载器。

系统加载器:

Bootstrap ClassLoader(引导类加载器)

底层用C/C++代码实现的加载器,用于加载指定的核心类库。它用来加载以下目录中的类库:$JAVA_HOME/jre/lib目录和-Xbootclasspath参数指定目录。

Extensions ClassLoader(扩展类加载器)

用于加载Java的扩展类,提供除了系统类之外的额外功能。它用来加载以下目录中的类库:$JAVA_HOME/jre/lib/ext目录和java.ext.dir指定目录。

Application ClassLoader(应用程序类加载器)

它用来加载以下目录中的类库:当前应用程序的ClassPath目录和系统属性java.class.path指定目录。

自定义加载器:自定义加载器是通过继承java.lang.ClassLoader类的方式来实现自己的类加载器的。

4.运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为不同的数据区域,这些区域分别为程序计数器、Java虚拟机栈、本地方法栈、Java堆和方法区。

1.程序计数器

为了保证程序能够连续的执行下去,处理器必须具有某些手段来确定下一条指令的地址,而程序技术器就是起到这种作用。程序计数器是Java虚拟机规范中唯一没有任何规定OutOfMemoryError情况的数据区域。

2.Java虚拟机栈

每一条Java虚拟机线程都有一个线程私有的Java虚拟机栈,它的生命周期与线程相同,与线程是同时创建的。Java虚拟机栈存储线程中Java方法调用状态,包括局部变量、参数、返回值以及运算的中间结果等。

3.本地方法栈

Java虚拟机实现可能要用到C Stacks来支持Native语言,这个C Stacks就是本地方法栈。它与Java虚拟机栈类似,只不过本地方法栈是用来支持Native方法的。

4.Java堆

Java堆是被所有线程共享的运行时内存区域。Java堆用来存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆存储的对象被垃圾收集器管理。Java容量可以实固定的,也可以是动态扩展的。Java堆所使用的内存在物理上不需要连续,只要在逻辑上连续即可。

5.方法区

方法区是被所有线程共享的运行时内存区域,用来存储已经被Java虚拟机加载的类的结构信息。方法区是Java堆的逻辑组成部分,它一样在物理上不需要连续。

6.运行时常量池

运行时常量池是方法区的一部分,它用来存放编译时期生成的字面量和符号引用,这些内容会在类加载后存放在方法区的运行时常量池中。

三.对象的创建

当我们创建对象时一般是通过new指令来完成一个对象的创建的,当虚拟机收到一个new指令时,它会做如下操作:

1.判断对象对应的类是否加载、链接和初始化

2.为对象分配内存

3.处理并发安全问题

4.初始化分配到内存空间

5.设置对象的对象头

6.执行init方法进行初始化

四.对象的堆布局内存

对象创建完毕,并且已经在Java堆中分配了内存,而对象在堆内存的布局分为三个区域,分别是对象头、实例数据和对齐补充:

对象头

对象头包括两部分信息,分别是Mark World和元数据指针。Mark World用于存储对象运行时的数据,而元数据指针用于指向方法区中的目标类的元数据,通过元数据可以确定对象的具体类型。

实例数据

用于存储对象中的各种类型的字段信息。

对齐填充

对齐填充不一定存在,只是起到了占位符的作用。

五.垃圾标记算法

1.垃圾收集器

垃圾收集器,通常是被称作GC,其主要任务有两个,一个是内存的划分和分配,另一个是对垃圾进行回收。在对垃圾进行回收之前,GC要先标出垃圾,目前主流的有两种垃圾标记算法:引用计数算法和根搜索算法。

2.Java中的引用

Java将引用分为强引用、软引用、弱引用和虚引用。

强引用

当新建一个对象时就会创建一个具有强引用的对象,如果一个对象具有强引用,垃圾收集器就绝不会回收它。

软引用

如果一个对象只有软引用,则当内存不够时,会回收这些对象的内存。Java提供SoftTrference类来实现软引用。

弱引用

弱引用比起软引用具有更短的生命周期,垃圾收集器一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会回收它。

虚引用

虚引用不会决定对象的生命周期,如果一个对象仅持虚引用,就相当于没有任何引用一样,在任何时候都可能被垃圾收集器回收。

3.引用计数算法

基本思想:每个对象都有一个引用计数器,当对象在某处被引用的时候,它的引用计数器就+1,引用失效的时候就-1,当引用计数器中的值变为0,则该对象就不能被使用,也就变成了垃圾。

缺点: 引用计数算法没有解决对象之间相互循环引用的问题,举例来说:

public class Test{

public static void main(String[] args){

Object obj1 = new Object();

Object obj2 = new Object();

obj1.instance = obj2; //引用

obj2.instance = obj1;

obj1 = null; //此时已经无效,可以回收

obj2 = null;

System.gc(); //打印gc日志

}

}

4.根搜索算法

基本思想: 选定一些对象作为GC Roots,并组成根对象集合,然后以这些GC Roots的对象作为起始点,向下搜索,如果目标对象到GC Roots是连接着的,这些目标就称为可达的,如果目标对象不可达则说明目标对象是可以被回收的对象。

在Java中,可以作为GC Roots的对象主要有以下几种:

1)Java栈中引用的对象。

2)本地方法栈中JNI引用的对象。

3)方法区中运行时常量池引用的对象。

六.Java对象在虚拟机中的生命周期

创建阶段(Created)

创建阶段的具体步骤为:

1)为对象分配存储空间。

2)构造对象。

3)从超类到子类对static成员进行初始化。

4)递归调用超类的构造方法。

5)调用子类的构造方法。

应用阶段(In Use)

在创建阶段之后,对象的状态就切换到了应用阶段。这个阶段的对象至少具有一个强引用,或者显示的使用软引用、弱引用或者虚弱引用。

不可见阶段(Invisible)

此时在程序中找不到对象的任何强引用,但是该对象仍可能被特殊的强引用GC Roots持有着(可达)。

不可达阶段(Unreachable)

在程序中找不到对象的人和强引用,并且垃圾收集器发现对象不可达。

收集阶段(Collected)

垃圾收集器已经准备好要对该对象的内存空间重新进行分配,这个时候如果该对象重写了finalize方法,则会调用该方法。

终结阶段(Finalized)

在对象执行完fnialize方法后仍然处于不可达状态时,或者对象没有重写finalize方法,则对象会进入终结阶段,并等待垃圾收集器回收该对象空间。

对象空间重写分配阶段(Deallocated)

垃圾收集器对对象的内存空间进行回收或者再分配,此时该对象会彻底消失。

七.垃圾收集算法

1.标记-清除算法

基本概念:垃圾清除算法将垃圾收集分为两个阶段:标记阶段(标记出可回收的对象)和清除阶段(回收被标记对象)。

缺点: 首先是标记和清除的效率都不高,还有就是容易产生大量不连续的内存碎片,碎片太多可能会导致后续没有足够的连续内存分配给较大的对象。

2.复制算法

基本概念: 它把内存空间划分为两个相等的区域,每次只使用其中一个区域。在垃圾收集时,遍历当前使用的区域,把存活的对象复制到另一个区域中,最后将当前使用区域的可回收对象进行回收。

缺点: 系统的使用内存减半,同时复制算法的效率和存活对象的数目有很大的关系,如果存活对象很少,则复制算法的效率就会很高。复制算法广泛用于新生代中。

3.标记-压缩算法

基本概念:首先标记内存中可以回收的对象,然后将所有存活的对象压缩到内存的一端,使它门紧凑的排列在一起,然后对边界以外的内存进行回收。标记-压缩算法被广泛应用于老年代中。

4.分代收集算法

分代的概念:分代收集算法会结合不同的收集算法来处理不同的空间。Java堆区的空间划分在Java虚拟机中,各种对象的生命周期会有着较大的差别,因此应该对不同的生命周期的对象采取不同的收集策略,根据生命周期的长短将它们分别放到不同的区域,并在不同的区域中采取不同的收集算法。Java堆区基于分代的概念,分为新生代和老年代。

分代收集: 根据Java堆区的空间划分,垃圾收集的类型分为两种:Minor Collection(新生代垃圾收集)和Full Collection(老年代收集)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值