【JavaEE】了解JVM

这篇具有很好参考价值的文章主要介绍了【JavaEE】了解JVM。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JVM的基本认识

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

【JavaEE】了解JVM

JVM是Java虚拟机(Java Virtual Machine)的缩写

  • 它是Java编程语言的关键组成部分。
  • JVM是一种用于在计算机上执行Java字节码的虚拟机。
  • 它是Java平台的核心技术,提供了跨平台的特性和Java的主要优点。

JVM的来历可以追溯到20世纪90年代初,当时Sun Microsystems(现在是Oracle Corporation的一部分)开发了Java语言。

  • Java的目标是在不同的硬件和操作系统平台上实现 “一次编写,到处运行” 的理念。
  • 为了实现这一目标,Sun Microsystems开发了JVM,它是Java语言的运行时环境。

接下来就是介绍JVM中重要的几个 芝士点

1. JVM中的内存区域划分

JVM其实就是一个java进程,java进程会从操作系统这里申请一大块内存区域,再进行一系列划分,给java代码使用~

  • 所以java程序不鼓励多进程,而鼓励多线程也是这个原因

而我们重点要学的是内存的进一步划分,不同的区域有不同的用途

1.1 JVM的核心区域

  1. ,java中实例化出来的对象,即成员变量
  2. ,维护方法之间的调用关系,即局部变量
  3. 方法区(旧说法)/元数据区(新说法),类加载之后的类对象,包括静态变量、方法…
    • 类对象就是.class文件的特殊数据结构构成的对象,类名.class去获取
    • 方法不是变量,其实在内存中是字节码(二进制指令)形式存在!

经典的面试题:

  • 给一段代码,问你某个变量处在内存中的哪个区域
  • 根据上面的变量形态与内存区域的对应即可~

注意:

  • 变量的类型与它在内存中的区域无关
Apple a = new Apple();

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 我们常常把a叫做引用,或者对象,其实它指向的内容,才是对象,才是属于堆的东西

记住java对象的这个核心关系即可:

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

1.2 JVM内存城防图

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

灰色:两个栈

  1. 虚拟机栈,给java代码使用的
  2. 本地方法栈,是给JVM内存的native本地方法使用的(JVM的本地方法内部是通过C++实现的)

之前的String常量池…也在元数据区里~

  • 不必多说~

Program Counter Register(程序计数器)

用途是记录当前程序执行到哪个指令~

  • 简单地用long类型的变量去存储 “一个内存地址”
  • 这个内存地址就是下一个要执行的字节码所在的地址

CPU也是有这么一个专门的寄存器,JVM参考了CPU

堆的细节安排,在垃圾回收策略里就体现出来了,随后讲解

堆和元数据区,在一个JVM进程中,只有一份;栈和程序计数器,则存在多份(每个线程只有一份)

2. JVM的类加载机制

类加载:把.class文件,加载到内存,得到类对象,这样的过程~

  • 程序要运行的必要条件:指令和数据

类加载的步骤,其实非常的复杂,而我们只需要理解一些基本流程

  • 可以去看看官方的规范:Java SE Specifications (oracle.com)
  • The Java® Virtual Machine Specification (oracle.com)

提到了 五个词

  1. 加载 - loading
  2. 验证 - verification
  3. 准备 - preparation
  4. 解析 - resolution
  5. 初始化 - initialization

2.1 loading

找到.class文件,并且读文件内容,获取到字节码

  • 涉及到一个经典的考点:双亲委派模型,在后面单独解释

2.2 verification

.class文件的数据格式:

  1. 二进制
  2. 类似c语言的结构体(JVM本质就是C++写的)

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • u4 => 无符号整型(四个字节)
  • u2 => 无符号整型(两个字节)
  • 其他就是JVM中定义的其他结构体

这一步就是验证这个.class文章的内容是否符合标准,感兴趣的可以去研究一下每个成员的含义~

2.3 preparation

给类对象分配内存空间

  • 这个是未初始化的空间,内存空间的数据是全是0的

2.4 resolution

解析,则是针对字符串常量,进行初始化

最主要是将“常量池的符号引用替换为直接引用”:

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

2.5 initialization

针对类对象进行初始化(初始化静态成员变量,静态方法,执行静态代码块,加载父类、内部类…)

第四第五步我觉得界限不明显,可能是本就是一步,比较这五个步骤是人为划分出来的

2.6 类加载触发的时机

并不是jvm一启动,就把所有的.class都加载了!整体是一个“懒汉模式”,非必要不加载

  1. 要创建这个类的实例
  2. 使用这个类的静态方法/静态属性
  3. 使用子类,会触发父类的加载
  4. 反射(使用类对象的场合)

2.7 双亲委派模型

因为这个好名字,成为了一个热门面试题,其实这个加载步骤在类加载中并不是什么关键的步骤~

接下来就来好好了解一下吧!

主要工作,在第一个步骤中,找.class文件的一个过程~

JVM中,内置了三个类加载器(加载类,需要用到的一组特殊模块)

  1. BootStrap ClassLoader,负责加载Java标准库中的类
  2. Extension ClassLoader,负责加载一些非标准的类,(Sun/Oracle扩展库的类)
  3. Application ClassLoader,负责加载项目中自己写的类,以及第三方库中的类

也可以自己去定义类加载器~

三个类加载器负责三组不同的目录~

当我们具体加载一个类的时候,需要先给定一个类的全限定类名“一系列包名.类名”,例如:“java.lang.String”

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java
双亲委派模型被称为“双亲”,是因为它建立了一个父子关系的类加载器层级结构,通过委派加载的方式提供了一种高效、安全和一致的类加载机制。就体现在两个委派方向咯~

其实是翻译的问题,双亲就是family~

3. JVM中的垃圾回收策略

JVM中帮助程序员自动释放内存的~

在C中,malloc的内存必须手动free,否则就容易出现内存泄露(只申请不释放,出现逐渐崩溃)

  • C++中的内存泄露不易发现,并且现象就像温水煮青蛙,很久才会被发现,并且发现的时候就一发不可收拾

java等后续的编程语言,引入了GC来解决这个问题~

GC的全称是垃圾回收(Garbage Collection)。在计算机科学中,垃圾回收是一种自动化的内存管理技术,用于在程序运行时自动回收不再使用的内存资源,以便重新分配给其他需要的对象。

当程序运行时,会动态地创建和销毁对象。由于对象的动态性,手动管理内存资源变得复杂和容易出错。垃圾回收器(GC)的作用就是在程序运行时监测和识别不再使用的对象,然后释放其占用的内存资源。

能够有效的减少内存泄露的出现概率!作死的一样会出现~

申请内存的时机是明确的,使用到了必须要申请

释放内存的时机是模糊的,完全不使用了才能释放

而C/C++将这个释放的时机,全权交给程序员,但是 java的JVM则通过一系列策略自动判断是否释放

  • 这些策略的准确性是比较高的,但是是需要代价的,那就是时间/空间

3.1 JVM释放的空间

  • 是堆,GC的主要目标

    • 不仅仅是java,C/C++中自主申请和释放的也是堆
  • 因为栈是局部变量,创建与销毁本就系统自动的行为(随着线程的销毁而销毁,汇编操作中(栈帧创建与销毁,即入栈和出栈)方法结束的出栈操作而被销毁)

  • 程序计数器,就一个long变量,随着线程销毁而销毁

  • 元数据区/方法区,存的类对象,很少会“卸载”,进程结束销毁~

而GC就是以对象为单位进行释放的,即释放内存=释放对象

  • 总不能释放半拉对象吧,🤣

3.2 GC的两个阶段

  1. 找,谁是垃圾(涉及垃圾回收算法)
  2. 释放,将垃圾对象的内存整体释放掉

接下来我们要了解一下垃圾回收算法,我们学习思想,不代表JVM的真实实现方法,JVM的实现方法是在此基础上的优化~

3.3 垃圾回收算法

一个对象,后续不再使用,就可以认为是垃圾~

java中使用一个对象,只能通过“引用”~

  1. 如果一个对象,没有引用指向它,此时这个对象一定是无法被使用的(妥妥的垃圾)
  2. 如果一个对象,已经不想用了,但是这个引用可能还被指向着(这个携带程序员主观意愿,JVM无法判断)
3.3.1 引用计数

不针对JVM的判断方法,python和PHP采取了一个算法:引用计数

就是给对象安排一个额外的空间,保存一个整数,表示该对象有几个引用指向它~

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 随着引用的销毁,计数就会减少,为0的时候,立即释放~

缺陷就是:

  1. 每个对象都需要怎么一个可见来存放这个计数

  2. 还有个漏洞,就是一些“循环引用”引起的问题,最典型的就是循环链表

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 这个时候,c1 = null; c2 = null;

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 计数并非为0,不能释放~
3.3.2 可达性分析

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

而这个算法,才是JVM采取的方案,并没有采取引用计数~

  • 我们可以把对象之间的引用关系,理解成一个“有向图结构”,从一些特殊的起点出发,进行遍历,只要能便利访问到的对象,就是“可达”,否则就是“不可达”
    • 不可达的就是垃圾咯~

例如下图,则就是一种复杂的引用关系~
【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 边的箭头我省略了

  • 然后我们就寻找其中特殊的起点(蓝),开始遍历,每个蓝色的都便利一边,访问的到的标记为“可达”,所有蓝点都便利完后,未被标记的就是“不可达”

  • 即顺藤摸瓜

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 而这个蓝色起点,可以是引用中的“局部变量”,因为我们是在方法内部可以先通过局部引用变量去访问堆区空间的,进而延申出后面的引用关系!
  • 其次,还可以是常量池上引用的对象,方法区中静态成员引用的对象
  • 这些蓝点有一个名称:GCroots

缺点:

  • 耗时及其大
  • 这个过程中,必须保证原代码的引用关系不要发生变化,所以要加锁,即STW问题
    • 加锁 -> 其他业务暂停工作,Stop the world!

随着java的发展,JVM的垃圾回收不断的更新优化,STW问题也被很好的应对,不能完全消除,但是STW的时间可以忽略不及了~

3.4 释放“垃圾”对象

接下来介绍三种典型的策略

3.4.1 标记释放

通过找的过程后,我们已经知道哪些是需要释放的了~

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

而“标记释放”则是直接将被标记为“不可达”的内存空间直接释放,虽然速率快,但显然,释放出来的空间,七零八落,这导致这些空间释放了之后,完整性不高,甚至可能导致之后无法再被申请!

  • 因为申请空间是需要一段完整的空间!
  • “产生内存碎片”

就相当于,你有2G的内存,但是不连续,都是内存碎片,这样就导致100M的空间都申请不出来~

3.4.2 复制算法

这种算法是将原本的堆去分为两个部分,一次只用其中一半:

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

而删除的时候,将“可达”的内存搬运到另一侧

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

然后这一侧,全部统一释放~

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

解决了“内存碎片”的问题,但是也很明显

  1. 若大部分要保留则搬运成本大
  2. 空间利用率低
3.4.3 标记整理

这种算法则是类似顺序表删除元素操作的方式:

  • 就是一个搬运的过程~
    【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • “不可达”的数据被覆盖

  • “搬运完成之后”,再对后面“不可达”的数据进行释放

解决了“内存碎片”的问题,但是缺点很明显:

  • 搬运开销还是比较大

    • 因素:
    1. 需保留的内存
    2. “不可达”的数据在内存中排的比较前
3.4.4 分代回收

对于前面三种策略其实各有千秋,但是都有缺点,而我们现在要做的就是,在他们适合存在的场合使用他们,将利益最大化,就衍生出算法“分代回收”,这也联系到“堆”的布局:

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

这就有一个概念:“年龄”

  • 对象的年龄:一个对象每经过一轮扫描(可达性分析),就涨一岁
  • 一个对象刚出生,我们认为是0岁

还有一个普遍的经验规律,或者说是一个代码习惯:

  • 一个对象年龄越长,这个对象就更可能存活更久时间;
  • 一个对象年龄曰小,这个对象就更可能被销毁

即,"要死的话早就死了"

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  • 伊甸是西方的说法,伊甸园是上帝创造的第一个人出生的地方~

分代回收过程如下:

  1. 新创建的对象,放到伊甸区,在伊甸区的对象,进行"标记释放"
  • 在第一轮”GC“存活下来的对象,移动至幸存区,S0/S1
  • 有绝大多数的对象在第一轮”GC“中就别释放了,采取“标记删除”的方式直接释放即可,因为不会出现内存碎片的问题,因为原可达数据已经被移走了

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  1. 在幸存区的对象,进行"复杂算法"
  • 因为在这个区域内的对象需要保留的比较少
  • 并且这个区域本来就小,不用担心内存利用率低的问题
  • 经过若干轮”GC“存活下来的对象,移动到老年代

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

  1. 在老年代的对象,进行"标记整理"
  • 因为在这个区域内能存活更长时间的内存都排列在前面了
  • 前面的能活得更久,后面的则更容易被释放,所以挪动次数被尽可能降低了
  • 不仅如此,在老年代,“GC”的频率降低
    【JavaEE】了解JVM,JavaEE,java-ee,jvm,java
  1. 特殊情况:在第一轮“GC”后,内存很大的存活对象,直接放进老年代
  • 内存很大,复制算法成本太高,放在老年代被后面的数据覆盖会更好
  • 并且大内存的对象,也不会很多

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java

贯彻这个过程的一句话就是:"要死的对象早就死了,活下来的就是有两把刷子的"

感兴趣的同学可以去学习“垃圾收集器”,这就是具体的实现方法了,有改进和优化…

  • CMS
  • G1
  • ZGC

认识越新的越好~

4. JMM

JMM的全称是Java内存模型(Java Memory Model)。

  • Java内存模型定义了Java程序中多线程并发访问共享内存的行为规范,确保多线程程序的正确性和可预测性。

Java内存模型主要关注的是多线程环境下的共享内存访问问题。

  • 在多线程编程中,多个线程同时访问和修改共享的变量和对象可能会导致不可预料的结果,如数据竞争、内存可见性问题等。
  • Java内存模型提供了一套规范,定义了一系列规则和原则,来约束线程如何协作和访问共享内存。

Java内存模型包含了对于线程之间的操作顺序、变量的可见性、原子性操作、内存屏障等方面的规范。

  • 它确保在满足规定的条件下,程序员可以正确地编写并发程序,而无需担心数据不一致或未定义行为。

通过定义内存访问规则和操作顺序,Java内存模型提供了happens-before关系的概念。

  • happens-before关系指定了对于不同线程之间操作的顺序性,确保线程之间的操作按一定的顺序发生,从而保证了程序的正确性。

Java内存模型的规范不仅仅适用于Java语言本身,也适用于运行在Java虚拟机上的其他语言。

  • 它为多线程编程提供了标准化的原则和规则,使得程序员能够更加方便地控制线程的行为,编写并发安全的程序。

总结而言,JMM的全称是Java内存模型,它定义了Java程序中多线程并发访问共享内存的行为规范,确保多线程程序的正确性和可预测性,提供了一套规则和原则来约束线程的协作和访问共享内存。

  • JVM和JMM是紧密联系的,JVM作为Java程序的运行环境,依赖于JMM的规范来保证多线程程序的正确性和可预测性。
  • JVM执行的字节码遵循JMM的规则,通过指定的线程安全机制和内存可见性保证线程间的正确通信和协作。

之前在讲多线程线程安全(内存可见性)的时候讲过了,传送门:【JavaEE】线程安全问题_s:103的博客-CSDN博客

【JavaEE】了解JVM,JavaEE,java-ee,jvm,java


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

总的来说,JVM不需要了解的太深,如果你能理解本篇文章,就足够了~

JavaEE的初阶内容已经结束,接下来将学习JavaEE的进阶内容,比如一些框架,敬请期待!文章来源地址https://www.toymoban.com/news/detail-560934.html


到了这里,关于【JavaEE】了解JVM的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • “深入剖析JVM内部机制:了解Java虚拟机的工作原理“

    标题:深入剖析JVM内部机制:了解Java虚拟机的工作原理 摘要:本文将深入剖析JVM内部机制,详细介绍Java虚拟机的工作原理。我们将探讨JVM的组成部分、类加载过程、内存管理、垃圾回收以及即时编译等关键概念。此外,还将提供示例代码来帮助读者更好地理解JVM的内部机制

    2024年02月11日
    浏览(42)
  • 《JavaEE初阶》JVM基础知识

    本章主要介绍JVM中比较重要的三个内容: JVM内存区域划分 JVM类加载机制 JVM垃圾回收机制 当我们创建一个java进程时,启动时会向操作系统申请一块内存,JVM会将这块内存划分为几个区域: 堆 栈 程序计数器 方法区 堆: 堆上主要存放的是new的对象,是最重要的区域,也是内存划分最多

    2024年02月09日
    浏览(37)
  • 【JAVAEE】JVM中垃圾回收机制 GC

      博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE初阶   上篇文章我们讲了java运行时内存的各个区域。 传送门:【JavaEE】JVM的组成及类加载过程_xyk:的博客-CSDN博客 对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线

    2024年02月16日
    浏览(44)
  • 【JavaEE】JVM的组成及类加载过程

    博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE初阶   本文我们主要讲解一下面试中常见的问题,如果想深入了解,请看一下《Java虚拟机规范》这本书 目录 文章目录 一、JVM简介 二、JVM整体组成 2.1 运行时数据区组成 2.2 小结 三、JVM类加载 3.1 类加载过程 四、

    2024年02月13日
    浏览(38)
  • JVM,关于JVM基础的知识,你确定不了解一下吗?

    目录 一.JVM的概念 什么是JVM? 二.JVM的运行流程 1.class文件如何被JVM加载并运行 2.JVM运行时数据包括哪些区域(M) 三.类加载的过程(M) 四.双亲委派模型 1.双亲委派模型分析 2.JAVA中有哪些类加载器(M) 五.垃圾回收机制 1.死亡对象的标识 ①引用计数算法 ②可达性分析算法

    2024年02月02日
    浏览(41)
  • JVM基础了解

            JVM 是java虚拟机。        作用: 运行并管理java源码文件锁生成的Class文件;在不同的操作系统上安装不同的JVM,从而实现了跨平台的保证。一般在安装完JDK或者JRE之后,其中就已经内置了JVM,只需要将Class文件交给JVM即可  写好的java源文件,会编译生成16进制的字

    2024年02月12日
    浏览(36)
  • JVM的元空间了解吗?

    笔者近期在面试的时候被问到了这个问题,元空间也是Java8当时的一大重大革新,之前暑期实习求职的时候有专门看过,但是近期秋招的时候JVM相关的内容确实有点生疏了,故在此进行回顾。 首先,我们应了解JVM的堆结构,主要有两个版本及Java7以及Java8。 元空间的前身-永久

    2024年02月12日
    浏览(42)
  • 【JavaEE基础学习打卡03】Java EE 平台有哪些内容?

    📜 本系列教程适用于Java Web初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。 🚀 文中白话居多,尽量以小白视角呈现,帮助大家快速入门。 🎅 我是 蜗牛老师 ,之前网名是 Ongoing蜗牛 ,人如其名,干啥都慢,所以

    2024年02月12日
    浏览(45)
  • 了解 JVM - 认识垃圾回收机制与类加载过程

    本篇通过介绍JVM是什么,认识JVM的内存区域的划分,了解类加载过程,JVM中垃圾回收机制,从中了解到垃圾回收机制中如何找到存活对象的方式,引用计数与可达性分析的方式,再释放垃圾对象时使用的方式,标准清除,复制算法,标准整理,分代回收等等,如有错误,请在

    2024年02月16日
    浏览(39)
  • 怎么拿Offer拿到手软?JVM、高并发、Spring、Netflix、Spring Cloud都要强化了解

    送书第一期 《用户画像:平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 送书第三期 《深入浅出Java虚拟机》 送书第四期 《AI时代项目经理成长之道》 送书第五期 《Kubernetes原生

    2024年02月05日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包