JVM:基础回顾

一、Java
1.1 Java 技术体系包含什么?

Java 技术体系包含Java 程序设计语言Java 虚拟机Class 文件格式Java API 类库
各部件关系

  • Java 程序设计语言:也就是 Java 语言,包括各种定义、规范等;
  • Java 虚拟机:各种硬件平台上的虚拟机;
  • Class 文件格式:简单的说就是把 Java 代码转换为二进制、格式为 .class 的文件,方便在各个平台被虚拟机读取;
  • Java API 类库:Java 提供的 API,方便开发者日常使用。比如日历 Calendar,数学计算 Math 等;
  • 来自商业机构和开源社区的第三方 Java 类库:也就是第三方库。
1.2 什么是 JDK?

JDK 是 Java Development Kit(Java开发工具)的简称,也就是说要开发 Java 程序,需要的一些组件。

  • Java 语言;
  • Java 虚拟机;
  • Java API。

我们安装 JDK 的时候,一般都包含上述内容。

1.3 什么是 JRE?

Java Runtime Environment(Java运行环境)的简称,也就是说要跑 Java 代码,需要哪些什么样的运行环境支持。

  • 用户界面工具集:
  • 各种 API 库;
  • Java 虚拟机。

JRE 被包含于 JDK 中,我们可以只选择安装 JRE 用来跑 Java 而不是用来开发。

二、JVM
2.1 什么是 JVM?
定义:

Java 虚拟机是一种抽象化的计算机,在实际上的计算机模拟各种计算机功能来实现。

正是因为模拟了一台计算机,所以可以方便地在其它计算机环境下运行。
就比如市面上的 GBA、NES 游戏模拟器,模拟了游戏运行环境,可以在手机、电脑等设备上运行,实现执行游戏文件的功能。Java 也是类似的过程实现了跨平台运行。

JVM 数据类型

2.2 JVM 支持的数据类型

JVM 操作的数据类型也可以分为两类:

  • 原始类型:类似 int、short、byte、long。存在原始值,运行时可以利用虚拟机字节码进行数据操作。
  • 引用类型:存在引用值,用于变量赋值、参数传递、方法返回和运算操作。JVM 使用 reference 类型来表示对象的引用,可以指向实例或者数组。

JVM 希望尽可能多的在编译期完成类型检查,这样在运行期就无需动态确认类型了。

原始类型:
类型位数默认值取值范围
byte8位有符号0-128(-2^7)~ 127(2^7-1)
short16位有符号0-32768(-2^15)~ 32767(2^15 - 1)
int32位有符号0-2,147,483,648(-2^31)~ 2,147,483,647(2^31 - 1)
long64位有符号0-9,223,372,036,854,775,808(-2^63)~ 9,223,372,036,854,775,807(2^63 -1)
char16位无符号Unicode 的 null (’\u0000’)\u0000 ~ \uffff
float单精度、32位0-
double双精度、64位0-
booleanOracle公司的虚拟机编码为 byte 数组,每个 boolean 占 8 位0-false 1-true-
引用类型:

JVM 引用类型包含三种:

  • 类类型:指向类实例;
  • 数组类型:指向数组实例;
  • 接口类型:实现某个接口的类或数组实例。
2.3 JVM 运行时数据区域

虚拟机运行的时候会把内存划分为若干个不同的区域
虚拟机运行时区域

1. 程序计数器(pc寄存器)
定义:

程序计数器又称 pc(program counter) 寄存器,用来储存下一条指令执行的地址。

作用:
  • 是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令;
  • 如果线程执行的 Java 方法,记录的是正在执行的虚拟机字节码指令的地址,如果是 Native 方法,计数器值为空(Undefined)。
特点:
  • 很小的内存区域;
  • 线程私有:每一条线程都会有自己的 pc寄存器,因为 cpu 可能会随时切换执行的任务,所以有必要给每条线程创建 pc寄存器 以确认下面该执行什么任务;
  • 唯一一个没有定义 OutOfMemoryError 的区域;
  • 跟随线程的生命周期。
2. Java 虚拟机栈

Java 虚拟机栈是Java方法运行过程的内存模型。

作用:
  • JVM 在每一个方法执行的同时创建 “栈帧”,这块区域包含 局部变量表、操作数栈、动态链接、方法出口等信息;

    • 局部变量表: 存储的是编译期可知的基本数据类型(int、short、byte、long 等)、对象引用和 returnAddress 类型(指向一条字节码指令的地址);
    • 操作数栈:进行数据操作、准备调用方法的参以及接收方法返回结果;
    • 动态链接:将符号引用转化为直接引用。
  • 当方法运行时需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中,当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。

特点:
  • 线程私有:每个线程执行的方法可能不一样,所以需要分别创建;
  • 由一个个栈帧组成,栈帧包含方法出口信息,会在方法结束后该栈帧移出,释放内存;
  • 异常 StackOverflowError:如果栈帧数量超过虚拟机支持的最大容量,抛出这个异常;
  • 异常 OutOfMemoryError:动态扩展时,无法申请到足够内存,就会抛出此异常。

人们常说,Java的内存空间分为“栈”和“堆”,栈中存放局部变量,堆中存放对象。
这句话不完全正确!这里的“堆”可以这么理解,但这里的“栈”只代表了Java虚拟机栈中的局部变量表部分。真正的Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

本地方法栈:

主要用于为 Native 方法服务,与 Java 虚拟机栈的实现类似,也是可以创建一个个栈帧、也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

3. JVM 方法区image.png
作用:
  • 方法区用来存储已被 JVM 加载的类信息、常量、静态变量、即时编译后的代码等数据。
方法区主要包含内容:
  • 类型信息:
    • 类以及其超类的全限定名,也就是类的 包名+名字。比如 在 Class 文件中是 java/lang/Thread
    • 直接超接口的全限定名;
    • 类型标志:是类还是接口等;
    • 类访问权限符:public、private、default、abstract、final、static。
  • 类型的常量池:Class 文件中除了有类的信息,还有一项是常量池(Constant Pool Table),用于存放编译期生成的常量和符号引用。运行时会被加载进运行时常量池,使用时会把符号引用解析为直接引用;

符号引用:字面上的一个引用,作为标识用。因为编译期无法获取到该类的实际地址,只能用符号来表示地址。

  • 字段信息:修饰符(public、protect、private、default)、字段的类型、字段名称;

  • 方法信息:也就是这些类的所有方法包含的信息

    • 方法的返回值,包含 void;
    • 方法参数的类型、数目以及顺序;
    • 方法的修饰符(public、protect、private、default)
    • 方法字节码:
    • 方法中局部变量区的大小、方法栈帧
    • 异常表
  • 类变量(静态变量):

  • ClassLoader 的引用:用于加载动态链接

  • 指向该 Class 实例的引用:通过Class.forName(StringclassName)来查找获得该实例的引用,然后创建该类的对象。

  • 方法表:为了提高访问效率,JVM 可能会创建一个数组来存放非抽象类方法的直接引用。

特点:
  • 线程共享;
  • 永久代:存放的内容生命周期较长;
  • 内存回收效率低;
  • 虚拟机对其实现要求较松:允许固定大小,也允许可扩展的大小,还允许不实现垃圾回收。
运行时常量池:

方法区中存放三种数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。

作用:
  • 用于存放编译期生成的各种字面常量(public static final 声明的常量)和符号引用:
  • 运行时也可以创建常量并放入常量池中,比如 String 的 intern() 方法。
特点:
  • 具备动态性;
  • 会 OOM;
4. 堆

用来存放对象的空间。

作用:
  • 基本所有的对象都储存在堆中。
特点:
  • 线程共享;
  • 在虚拟机启动时创建;
  • 垃圾回收的主要场所;
  • 新生代、老年代:不同的区域存放具有不同生命周期的对象,便于回收;
  • 堆的大小既可以固定也可以扩展:当内存不足时,OOM。
5. 直接内存

直接内存是除Java虚拟机之外的内存,但也有可能被Java使用。

在NIO中引入了一种基于通道和缓冲的IO方式。它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需先将外面内存中的数据复制到堆中再操作,从而提升了数据操作的效率。

直接内存的大小不受Java虚拟机控制,但既然是内存,当内存不足时就会抛出OOM异常。

参考资料:

https://blog.csdn.net/dc2222333/article/details/82940649
https://blog.csdn.net/zero__007/article/details/100061611
https://blog.csdn.net/qq_41701956/article/details/81664921

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值