当前位置: 首页 > news >正文

JVM虚拟机--JVM的组成

(一)JVM的组成

在这里插入图片描述

一、JVM介绍

(1)JVM的作用

我们知道,Java代码要想在计算机中正常运行,就需要经过编译为class二进制字节码文件,而JVM就提供了class二进制字节码的运行环境。
在这里插入图片描述

  1. 一次编写,到处运行
    因为JVM是运行在操作系统当中的,通过屏蔽掉不同操作系统之间的差异,来实现自己作为跨平台语言的这种特性。因为无论在任何操作系统当中真正运行代码的不是这些操作系统,而是JVM,所以才能做到一次编写,到处运行
  2. 自动内存管理,垃圾回收机制
    与C语言相比,C语言需要程序员自行管理内存,如果编码不当很容易出现内存泄漏的现象。而Java虚拟机自带的垃圾回收机制就大大减轻了程序员的负担,减少出错机会。

(2)JVM的组成部分与运行流程

在这里插入图片描述

  1. Java Source
    指的是我们自己编写的Java代码,也就是.java文件
  2. Java Class
    将java文件编译为class文件
  3. 类加载子系统
    用于将java代码转换为字节码
  4. 运行数据区
    主要作用是把字节码加载到内存当中,因为程序必须要加载到内存才能运行。
    具体其他模块的功能将在后面进行细致介绍。
  5. 执行引擎
    用于把字节码翻译为底层系统指令。
    解释器:用于解释字节码信息:即使编辑器:会针对你的代码进行优化;GC垃圾回收:主要指的是运行数据区中的堆空间,后期将重点去讲解该垃圾回收机制。
  6. 本地方法接口与本地库
    由C/C++来实现,因为Java代码有时候并不能完全实现某些功能,只需要去记住系统提供的接口,再去进行调用即可。

(3)学习什么

在这里插入图片描述
在这里插入图片描述

二、程序计数器

在这里插入图片描述
线程私有的也就没有线程安全问题,因为每一个线程内部都有这样一个程序计数器。
在Java程序的class字节码文件中详细说明了代码的执行过程。
要想查看class字节码的信息就可以通过javap命令来查看字节码的反汇编信息:
在这里插入图片描述
在这里插入图片描述
这里面详细记录了main方法的执行过程,并且可以发现原来一行的sout打印代码被拆成了多行来执行。左侧代码的执行地址(0,3,5,8)可以理解为代码的执行行号。

  1. getstatic代表获取一个静态的变量,而System命令的out属性其实就是一个静态变量,类型是PrintStream。
  2. ldc加载常量,这里指的是String类型的字符串(hello world)。
  3. invokevirtual表面将要去调用的方法(println)。
  4. return指的是结束该方法。
    在这里插入图片描述
    假设现在在多线程环境下,要去执行当前代码,程序计数器就会给每一个线程去记录该行号。并且假设此时存在两条线程互相争夺执行权,线程1执行到第9行代码时被线程2夺走执行权,那么等线程2执行完毕或是线程1夺回执行权后,就会从先前执行到的第9行代码继续执行。

总结:

在这里插入图片描述

三、堆的详细介绍

(1)堆的介绍

在这里插入图片描述
1.线程共享区域肯定就会存在线程安全问题。
2.堆的划分
堆中又划分为了两个主要部分:年轻代与老年代;年轻代划分的三种类型Eden、S0、S1也存在一定区别,而S0、S1也被称为Survivor幸存者区。
通常情况如下:一个对象进来后先到Eden区,假如该对象在垃圾回收后依然存活,它就会被复制移动到S0或S1,且在挪动达到一定次数后也仍然存活,就会被放到老年代当中,老年代主要指的是生命周期比较长的对象。
而对象的挪动规则将会在后期讲解垃圾回收机制时会再详细说明。
3.元空间的作用
用于保存类的信息、静态变量、常量、编译后的代码。

(2)Java1.7与1.8的堆的区别是什么

在Java1.8之前,堆的区域当中还存在一个永久代,它的作用与元空间一样。
在这里插入图片描述
到了Java1.8之后,它把方法区/永久代放到了本地内存当中,也就是元空间中。为什么要放到本地内存:因为元空间与方法区主要存储的是一些类或常量,而随着项目运行时加载的类越来越多,这块方法区就会变得不可控,容易出现内存溢出或浪费内存,所以到了Java1.8优化过后就把他们都放到了本地内存,能够让堆来节省空间,最终目的都是避免OOM(内存溢出)

(3)总结

在这里插入图片描述

四、虚拟机栈

(1)什么是虚拟机栈

因为虚拟机栈是每个线程在运行时所需要的内存,多个线程运行时就会创建多个虚拟机栈,所以栈内存也是线程安全的
在这里插入图片描述

面试题:

在这里插入图片描述
在这里插入图片描述

  1. 垃圾回收是否涉及栈内存
    栈帧弹栈后释放内存的过程并不需垃圾回收器

(2)栈内存溢出情况

在这里插入图片描述

(3)总结

在这里插入图片描述
在这里插入图片描述

五、方法区

(1)方法区概述

在这里插入图片描述
元空间当中的Class用于存储类的信息,包括类的结构、方法、字段等;Classloader就是类加载器;运行时常量池将会在后面详细介绍。
通过Java代码来模拟本地内存溢出的情况:
因为元空间的默认大小是没有上限的,要想模拟内存溢出的情况首先就需要设置元空间大小上限为8m
在这里插入图片描述
在这里插入图片描述
执行该段代码,发现控制台中会提示元空间大小过小
在这里插入图片描述

(2)常量池

在这里插入图片描述

(3)运行时常量池

在这里插入图片描述

(4)总结

在这里插入图片描述

六、直接内存

(1)直接内存介绍

在这里插入图片描述
既然是操作系统的内存,那么是可以使用java程序来使用它的。
我们平时的IO是BIO,此处的NIO要比BIO的吞吐量高很多。

(2)常规IO数据拷贝流程

在这里插入图片描述
Java本身并不具备磁盘读写的能力,要想进行磁盘读写就必须调用操作系统所提供的函数,也就是本地的native方法。
常规IO的问题:在内存当中有两块缓冲区,这样读取数据时就必须要去读取、存储两份。因为java代码本身是访问不到系统缓冲区的,必须要把数据读到java缓冲区后才能使用java代码进行操作。这样就造成了一个不必要的数据复制,因此效率就比较低。

(3)NIO数据拷贝流程

在这里插入图片描述
这里出现的直接内存就相当于在操作系统中划出了一块缓冲区,可供系统与java代码共同访问,也就是共享的内存区域。这样java代码操作起来就非常方便了,提高运行效率,比较适合文件的IO操作。

(4)总结

在这里插入图片描述

相关文章:

  • PyTorch深度学习框架60天进阶学习计划 - 第46天:自动化模型设计(一)
  • 虚拟现实(VR)技术在教育领域的创新应用
  • 某局部三层休闲娱乐中心建筑设计与结构设计
  • 【GlobalMapper精品教程】094:GlobalMapper26简体中文版安装教程(附安装包下载)
  • Docker Overlay 网络的核心工作(以跨节点容器通信为例)
  • Java集合及面试题学习
  • C# 变量||C# 常量
  • 计算机网络 3-4 数据链路层(局域网)
  • QML Label 组件
  • BZOJ P1419 Red is good
  • 【leetcode100】分割等和子集
  • Linux 进程信号详解
  • ping: socket: Operation not permitted
  • AI调试工具有哪些?
  • 【漫话机器学习系列】211.驻点(Stationary Points)
  • CANFD技术在新能源汽车通信网络中的应用与可靠性分析
  • 论文阅读:2025 arxiv AI Alignment: A Comprehensive Survey
  • 深入理解 Java 多线程:锁策略与线程安全
  • 使用 Vite 快速搭建现代化 React 开发环境
  • 小程序 GET 接口两种传值方式
  • 译者手记|如何量化家庭历史
  • 融创中国披露二次境外债重组方案:总规模约95.5亿美元债全额转股权,孙宏斌部分受限股票6年内不得处置
  • 北京航空航天大学强基计划今年新增4个招生培养方向
  • 商务部:对原产于日本的进口电解电容器纸继续征收反倾销税
  • 中马签署互免签证协定,外交部:将进一步促进双边人员往来和交流合作
  • 习近平在马来西亚总理安瓦尔举行的欢迎宴会上的致辞