【Java EE】-JVM

news/2024/5/19 16:10:42/文章来源:https://blog.csdn.net/m0_63979882/article/details/131437565

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【JavaEE】
分享:
雨下整夜
我的爱溢出就像雨水
——《七里香》

主要内容:JDK,JRE,JVM三者之间的联系。JVM内存区域划分:本地方法栈(Native Method Stacks),虚拟机栈(JVM Stacks),程序计数器(PC),堆区(Heap),元数据区(MetaSpace)。JVM类加载机制,JVM类加载时机,JVM类加载过程,JVM类加载方式(双亲委派模型)。JVM垃圾回收机制(GC),如何判定一个对象是垃圾?看是否有引用指向这个对象。如何清理垃圾?标记清除,复制算法,标记整理,分代回收算法。

在这里插入图片描述

文章目录

    • 一、JDK JRE JVM
    • 二、JVM 内存区域划分
    • 三、JVM 类加载机制
      • 1)类加载时机
      • 2)类加载的过程
      • 3)双亲委派模型(类加载的方式)
    • 四、JVM 垃圾回收机制
      • 1)什么是 GC
      • 2)GC 如何判定对象是否是垃圾
        • 2.1> 引用计数
        • 2.2> 可达性分析
      • 3)GC 如何清理垃圾
        • 3.1> 三个基本回收算法
          • a 标记清除
          • b 复制算法
          • c 标记整理
        • 3.2> 分代回收算法
        • 3.3> 垃圾回收器

一、JDK JRE JVM

问题·:我们都知道,要想在电脑上运行Java程序,首先得安装上jdk,那么jdk是啥?它是拿来干啥的?为啥安装好jdk后就可以运行Java程序了?

JDK: 全称 Java Development Kit(Java开发工具包),包含Java运行时环境(JRE),Java开发工具。Java开发工具又包含Java编译器(Javac),Java学习文档和代码示例等。
Javac负责将Java源代码编译为字节码文件(.class文件)。

JRE: 全称 Java Runtime Environment(Java运行时环境),包含Java虚拟机和Java类库(Java标准库和API)。

JVM:全称Java Virtual Machine(Java虚拟机):
JVM 负责将Java字节码翻译成计算机可执行的机器码,并提供了一系列的运行时环境支持。
Java虚拟机中包含:
类加载器(Class Loader) :负责将编译后的字节码加载到内存中。
执行引擎(Execution Engine):负责执行加载到内存中的字节码。
运行时数据区(Runtime Data Area):包含了Java程序运行时所需要的内存空间,如方法区、堆、栈等。
垃圾回收器(Garbage Collector):负责自动回收不再使用的对象所占用的内存空间。


总的来说:JDK和JRE以及JVM的关系如下,(如下图所示):
JDK = JRE + Java开发工具
JRE = JVM + Java核心类库

在这里插入图片描述

解答:了解了上述的JDK、JRE、JVM后,我们不难理解,当我们安装好JDK后,就可以使用JDK中的Java编译器 将Java源代码编译成字节码文件,然后使用JRE中的 JVM来执行这些 字节码文件。JVM会将字节码翻译成计算机可执行的机器码,并提供运行时环境支持,使得Java程序能够在计算机上运行。

二、JVM 内存区域划分

在这里插入图片描述

可分为五个部分:
① 本地方法栈(Native Method Stacks):
用于记录native方法调用。是给要调用的 native方法(是由C/C++实现的JVM内部的方法)准备的栈空间。
② 程序计数器(Program Counter Register):
简称PC,PC存储着当前线程即将执行的指令的地址。
③ 虚拟机栈(JVM Stacks):
用于记录方法调用。每个线程有一份虚拟机栈,当该线程中有一个方法调用时,会在虚拟机栈中申请一个栈帧(开辟空间空间),并记录下当前方法的调用关系。每个栈帧会包含入口地址,参数值、局部变量、返回地址等等。
注意:每个线程中调用方法时,会为方法申请函数栈帧,这个函数栈帧是在虚拟机栈中的,一个线程对应一个虚拟机栈,而虚拟机栈中的一个栈帧对应一个方法调用。

④ 堆区(Heap):
new出来的对象,都是在堆上的。因此堆的空间比其他空间大很多。一个进程对应一个堆,该进程中的线程共享该堆空间。堆的空间会使用垃圾回收机制。
⑤ 元数据区(Metaspace),或方法区:
用于存储类对象、常量池、静态成员。JVM虚拟机加载解析好.class文件后,会将类对象保存到这里。
注意:每个Java程序在运行时都会创建一个Java虚拟机(JVM)实例,一个进程对应一个Java虚拟机,同时一个进程有一个堆和一个元数据区。

三、JVM 类加载机制

1)类加载时机

在Java程序启动时,首先使用javac编译将源文件(.java)编译生成字节码文件(.class),然后由Java虚拟机(JVM) 解析和执行字节码文件,最开始是将包含“main”方法的主类加载并解析;程序运行过程中,后续需要使用其他类的时候,再进行所需类的类加载操作。

类加载是在Java程序运行过程中第一次使用类时发生的。包含下面几种触发情况:
① 创建类的实例对象时,会先进行类加载。比如 new 一个对象时,会先加载这个对象所属的类。
② 访问类的 静态成员(静态变量,静态方法)时,触发类加载。
③ 使用反射机制访问类时,会先类加载。如获取类的class对象,调用类的方法等,都会先进行类加载。
④ 当启动Java程序时,会先加载包含"main"方法的主类。

2)类加载的过程

在这里插入图片描述

在Java中,类加载的过程由三个阶段组成:加载(Loading)、连接(Linking)、初始化(Initialization)。其中,连接阶段又包括验证(Verification)、准备(Preparation)、解析(Resolution) 三个步骤。下面我们就来了解这些阶段分别做了什么。

Loading:加载阶段,通过类的名字来查找编译后生成的对应类的字节码文件,并将字节码文件读取到内存中。
Linking:连接阶段包含三个部分。

Verification:验证字节码文件的正确性和安全性,确保符合Java虚拟机规范。
Preparation:准备,为类对象分配空间,并将内存空间赋予默认值"0",保存部分类信息。
Resolution:解析,对常量池进行初始化,虚拟机将常量池中类或接口等的符号引用转换成直接引用,以便定位到实际的内存空间。(在解析阶段,虚拟机会根据符号引用的信息,通过在方法区中查找类信息(在Preparation阶段保存的),来找到对应的直接引用)

注解:符号引用是一种以符号形式进行引用的方式,它包括类的名称、方法描述等,但是不具体指向实际空间上的某个位置。而直接引用则是内存中直接指向目标空间的指针、偏移量等。

Initialization:初始化,对类的对象进行真正的初始化操作,比如执行构造方法,执行静态代码块代码等。

3)双亲委派模型(类加载的方式)

1> 什么是双亲委派模型?
在Java中,所有的类都需要 类加载器(ClassLoader) 进行加载才能被JVM识别和使用。
双亲委派模型就是类加载器的一种工作机制:当一个类加载器加载一个类时,它会首先将加载请求交给父类加载器去完成,直到父类加载器无法加载时,才由子类加载器加载。需要注意的是:这里的父类加载器和子类加载器之间不是继承关系,而是理解为层次关系。

在这里插入图片描述

2> 双亲委派模型包含哪些来加载器?
如上图就是一个双亲委派模型(用户自定义添加了类加载器)
·BootstrapClassLoader·是启动类加载器,负责加载标准库中的类。ExtensionClassLoader是扩展加载类,负责加载JVM开发厂商提供的扩展库中的类。
ApplicationClassLoader是应用库扩展类,负责加载用户代码中的第三方库和项目中的类。
下面两个是用户自定义类加载器,可有可无。根据用户自己的需求而定。

3> 例子理解

举个例子,比如上图中,此处需要加载一个类时,会先从自定义加载器开始,但是自定义加载器不会直接进行这个类的加载,而是将加载请求交给它的父类加载器ApplicationClassLoader。但是AppClassLoader也不会直接进行这个类的加载,而是将加载请求交给它的父类加载器ExtensionClassLoader。ExtensionClassLoader也不会直接进行加载,而是将加载请求交给其父类加载器BootstrapClassLoader。BootstrapClassLoader会想要将加载请求交给它的父类加载器,但是它的父类加载器为null了,因此BootstrapClassLoader就根据要加载的这个类信息查找负责自己加载的标准库的相关类,如果找到就加载,如果找不到就算了。接着交给ExtensionClassLoader,也是查找自己负责加载的扩展库中的相关类,找到就加载,找不到就算了。然后交给ApplicationClassLoader,进行相应操作,如果还有自定义加载器也是一样。
总的来说:和是类似递归的方式实现。

4> 双亲委派模型的优点?
优点:它可以保证Java类的安全性和一致性。 比如你自定义实现了一个Integer类时,类加载的双亲委派模型方式会先使用父类加载器进行加载,因此会先加载到标准库中的Integer,这样可以防止和冲突。


注意:双亲委派模型也不一定要必须遵守。具体情况看需求。

四、JVM 垃圾回收机制

1)什么是 GC

1> GC,全称Garbage Collection,垃圾回收机制。

理解GC
我们知道,在C/C++中可以动态申请内存空间(malloc),这一部分的空间是在堆上的,当我们的程序不再需要使用这部分空间时,需要手动将动态申请的这一部分空间释放(free)掉,防止发生内存泄漏。
GC就是要做把不用的空间释放,归还给操作系统这样的操作。即GC就是Java虚拟机中的垃圾回收器自动帮我们回收了垃圾,而不需要我们手动回收垃圾,释放空间。像Java,python,Go,PHP,JS都是使用GC来解决垃圾回收的问题的。

问题1:我们知道,当进程关闭的时候(也就是退出程序),代码中开辟的空间就自动释放了。那么为啥必须将内存释放,似乎不释放也行?
解释:当程序作为客户端的程序的时候,确实是进程关闭,空间释放,即使是内存泄露一些也没多大影响,我把程序关了就行。但是,如果在服务器端就出大问题了,因为服务器7*24小时运行,很小的内存泄漏经过日积月累就很有可能成为一颗定时炸弹,不知道哪一天爆发。因此,应当时刻考虑内存泄露的问题。
问题2那么C/C++为啥不使用GC呢?
解释:原因是GC会消耗一定的资源,并且在垃圾达到一定量的时候进行清理时可能会出现卡顿问题,这个问题又称stw(Stop The World),但是C/C++追求的是极致的性能,因此没有采用GC来进行垃圾回收,而是需要程序员进行手动垃圾回收。

2> GC 的操作单位是对象,而不是字节

①垃圾回收(GC) 主要是针对堆区进行的。因为堆区是Java虚拟机分配对象内存的主要区域。
②垃圾回收(GC) 是以"对象"作为基本单位进行垃圾回收,即当这个对象的成员变量,方法等各种属性后续代码中不再用到时,就会进行垃圾回收。

3> GC 的实际工作流程

①找到垃圾,判定垃圾
②清理垃圾,释放空间

2)GC 如何判定对象是否是垃圾

问题:那么,怎么判断这个对象是否是垃圾呢?
核心思路:看是否有引用指向这个对象。

具体实现:
①引用计数
②可达性分析

2.1> 引用计数

在Python,PHP中的 垃圾回收(GC)使用的就是引用计数的方法。即给每个对象配备一个计数器,当有引用指向这个对象时,计数器+1,当引用被销毁时,引用-1。

引用计数进行垃圾判断的优缺点?
优点在于简单方便。
缺点在于:

有时内存浪费很多。当对象的空间很小且数量很多时,比如大量整形的对象(new Integer()),如果使用给这个对象配备一个计数器,那么就相当于增大了一倍的空间,浪费空间就很大。
存在循环引用的问题
举个例子,如下图:在指向下面的前两部分的代码后,1号对象和2号对象的引用计数都是2。当把car1和car2置为空,即不再指向它原来的对象时,可以发现1号对象和2号对象的引用都还是为1,这两个对象无法回收,本质就是car1的成员变量car还指向2号对象,car2的成员变量car还指向1号对象,但是car1和car2的car变量无法再被访问,因为car1和car2引用无了。
因此如果使用引用计数的方法来确定垃圾,还需要解决这个问题,在python和PHP中是搭配了其他机制,来解决循环引用的问题。
在这里插入图片描述

2.2> 可达性分析

①怎么进行可达性分析?
把new出来的对象,整体上串起来,类似于一个有向图。可达性分析时,使用根搜索算法,这个算法以一组"根"的起始对象开始,从这些根对象出发,递归遍历(DFS或BFS)所有的引用关系,标记所有可达的对象。再和所有对象的名单比对,不可达的对象就可以回收,释放空间。
我们再来看看引用计数的循环引用的问题在这里怎么样:不难发现,引用car1和car2的car已经无法找到,自然car1的car对2号对象的引用也就无法访问,进而就是2号对象不可达,car2的car对1号对象的引用无法访问,进而就是1号对象不可达,所以最后1号和2号对象都可以作为垃圾清除。

②根对象的选取?
虚拟机栈的栈帧中的局部变量引用的对象
方法区中的静态成员变量

3)GC 如何清理垃圾

基本方法有:标记清除、复制算法、标记整理三个算法。分代回收算法则是"复合型"算法,除此之外,还有并发标记算法CMS,还有G1,ZGC算法等。

3.1> 三个基本回收算法

a 标记清除

在可达性分析时,给所有可达的对象打上存活标记。在清除阶段,垃圾回收器遍历整个堆内存,清除未被标记的对象,相对而言就是清除标记为垃圾的对象。

标记清除的优点在于:简单方便。
缺点:内存碎片化。 如果后续需要在堆区申请一块大的空间,有可能因为内存碎片化的问题导致无法成功。

在这里插入图片描述

b 复制算法

将整个堆空间分成两半,首先使用左边一半(或右边一半也行),进行可达性分析后,就把可达的对象标记为存活对象,未标记的对象即相对的标记为垃圾的对象。当左边的空间达到一定的阈值时,会触发复制操作。将标记为存活的对象复制到右边,再把左边的整个空间全部释放。右边快满时,也做相应的操作。
复制算法优缺点:使用复制算法可以避免内存碎片化的问题。但是如果进行复制操作时,垃圾很少,但是存活的对象太多,这样复制的成本就大了。

在这里插入图片描述

c 标记整理

进行可达性分析后,就将可达的对象标记为存活,未标记的对象即为垃圾。整理时,从前到后将标记为存活的对象在这个空间里从前到后排列(可能会覆盖标记为垃圾的对象),然后把最后一个存活对象后面的所有空间释放。(类似于顺序表删除中间元素,有元素搬运的过程)

在这里插入图片描述

3.2> 分代回收算法

分代回收算法的核心是:分代,具体逻辑是,认为存在的越久的对象,之后也很可能长期存在。

怎么判断对象存在时间的长短?
分代回收算法依据在垃圾回收中存活下来的次数,将堆分成了新生代和老年代两个大的部分。新生代又分为Eden(伊甸区)和s0,s1幸村区。如下图所示:

在这里插入图片描述

分代回收算法怎么进行垃圾回收?
①新new出来的对象,会在伊甸区Eden开辟空间,经过一轮的可达性分析后,会将垃圾对象清除,一般来说剩下的存活对象就很少了,将存活的对象放入幸存区S1
②在幸存区S1中又经过一轮垃圾回收考验存活下来的对象则拷贝到S2,然后在S2中又经过一轮垃圾回收考验存活下来的对象则拷贝到S1,如此反复,达到一定次数的垃圾回收在幸存区还存活下来的对象就将它放到老年区。
③在老年区中,则会放缓垃圾回收的频率,如果垃圾回收扫描时,扫到了垃圾,使用标记整理进行垃圾回收。

分代回收算法是"复合型"算法,体现在哪里?
在幸存区中,进行s1和s2的轮换着复制,是复制算法,但是由于空间小,复制成本不高。在老年代中,使用标记整理的方式,由于幸存到老年代的对象其实很少,所以标记整理的整理成本也不高。

3.3> 垃圾回收器

实际上,我们所说的这些垃圾回收算法,在不同的垃圾回收器中有各自的实现。有的追求垃圾回收的效率高,有的追求垃圾回收时STW短等,具体看业务场景而定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_138845.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据分析 - 基础入门之NumPy③】日常难题解决

知识目录 前言一、启动Jupyter Notebook报错没有这样的目录结语# 往期文章&相关导读 前言 本篇文章用于整理在学习 NumPy 过程中遇到的错误,以此做个记录,希望能帮助到大家,让大家少走弯路。 一、启动Jupyter Notebook报错没有这样的目…

Delphi XE编写OCX控件

1、new->other 2、Active libary 3、再次New->Other,才出现ActiveX组件内容 设置类名及参数

开源预训练框架 MMPRETRAIN官方文档(概览、环境安装与验证、基础用户指南)

MMPretrain是全新升级的开源预训练框架。它已着手提供多个强大的预训练骨干网并支持不同的预训练策略。MMPretrain 源自著名的开源项目 MMClassification 和MMSelfSup,并开发了许多令人兴奋的新功能。目前,预训练阶段对于视觉识别至关重要。凭借丰富而强…

Docker 常用指令集合,更换镜像(Ubantu)

1.更换镜像 先进入root用户 cat /etc/docker/daemon.json 查看有没有镜像创建目录,创建并编辑damon,json文件 mkdir -p /etc/docker vim /etc/docker/daemon.json# 填写内容 {"registry-mirrors": ["https://h5rurp1p.mirror.aliyuncs.com"] } 重新启…

如何从零开始学习自动化测试?终于找到靠谱的教程了

目录 前言 测试基础 Python基础 selenium appium requests unittest 项目实战: 总结: 前言 最近有几个小伙伴在后台给安静私信说,如何学习自动化,不知道如何入手?在网上看的资料都是乱七八糟的,每…

VSCode编译github上面的C++项目

1、下载cmake 在这里下载对应的版本 https://cmake.org/download/ 测试下载的是这个 下载完成后安装,安装都比较简单 2、安装CMake工具扩展 3、安装C扩展 4、下载github项目 例如:下载这个项目 https://gitcode.net/mirrors/zrax/pycdc?utm_source…

使用凌鲨进行数据标注

在AI研发团队中,数据的数量和质量通常比算法本身更重要。为了获得大量高质量的数据,标注软件是必不可少的。目前许多开源标注软件在权限、任务管理和审核方面都存在较大问题。 在凌鲨(linksaas)0.3.8版本中增加了数据标注功能,支持 音频分类…

123.【SpringBoot 源码刨析B】

SpringBoot-核心功能 (三)、SpringBoot核心功能1.配置文件1.1、properties1.2、yaml(1).yaml 简介(2).yaml 基本语法(3).数据类型(4).示列 1.3、配置提示 2.WEB 开发1.SpringMVC自动配置概览2.简单功能分析(1).静态资源访问(1.1).静态资源目录&#xff0…

用真人模型制作3D虚拟人物,岂不是更真实?

3D虚拟人物是指利用计算机技术和图形学技术创建的一种能够模拟真实人体形态、行为和语言的虚拟实体。与传统的平面图像或视频不同,3D虚拟人物具有立体感和真实感,能够在虚拟环境中实现人机交互和情感交流,给用户带来全新的沉浸式体验。 随着…

国内环境安装Atlas OS步骤与网络问题解决

国内环境安装Atlas OS步骤与网络问题解决 Atlas 是一个开源、透明的项目,它修改了 Windows,并消除了影响游戏性能的所有负面缺点。我们是减少系统延迟、网络延迟、输入延迟和保持系统私密性的绝佳选择,同时仍然关注性能。我不久前在安装时遇…

【在线文件管理】响应式文件管理AngularJS

目录 1.功能展示截图 2.实现代码 2.1HTML页面代码 2.2后台代码 2.2.1项目结构 2.2.2项目代码 其他问题 1.功能展示截图 项目中需要用到文件管理来自由控制文件的上传、下载、删除等,就想到做一个简单的在线文件管理功能。 支持在线编辑: 2.实现代…

14 MFC多进程

文章目录 创建进程win32子进程内容创建进程传递参数关闭进程通过配置文件读取全部代码 打开进程便利进程 创建进程 分别创建MFC应用程序和Win32应用程序 MFC应用程序界面设置 win32子进程内容 #include <Windows.h> int WINAPI wWinMain(HINSTANCE hInstance, HINSTAN…

Java中的字符串类

提示&#xff1a;字符串类是编程中最常用的一种数据类型&#xff0c;比较重要❗ 文章目录 前言一、字符串类创建对象方式静态创建动态创建 二、String字符串内容不可改变三、字符串常用方法length方法charAt方法substring方法indexOf与lastIndexOfindexOf方法lastIndexOf方法 替…

Rust 动态数组Vec基本概念及其用法

目录 一、基本概念 Vec是什么&#xff1f; Vec的特点 (1)动态大小&#xff1a; (2)可变性&#xff1a; (3)泛型&#xff1a; 二、基础用法 1. 创建 (1) Vec::new()方法 (2) Vec::from()方法 (3) vec! 宏 2. 基础用法 三、Vec的简单实现及其宏模拟 四、leetcode 实…

如何在Linux下搭建接口自动化测试平台

我们今天来学习一下在Linux下如何搭建基于HttpRunner开发的接口自动化测试平台吧&#xff01; 需要在Linux上提前准备的环境&#xff08;下面是本人搭建时的环境&#xff09;&#xff1a; 1&#xff0c;Python 3.6.8 2&#xff0c;MySQL 5.7 一&#xff1a;下载HttpRunner…

【C语言基础】函数(2)

在函数&#xff08;1&#xff09;中我们已经讲过了函数的定义&#xff0c;形参与实参&#xff0c;函数的调用&#xff0c;局部变量与栈内存 接下来还有几个要强调的函数相关知识。 一、静态函数 静态函数是在函数声明前加上关键字 static 的函数。静态函数在C语言中具有以…

VisualSVN Server安装步骤

一.下载 官网&#xff1a;VisualSVN - Subversion-based version control for Windows 二.安装 双击安装 先创建好文件夹路径&#xff0c;建议放在同一个根目录下 三.安装成功&#xff0c;运行打开界面如图 四.创建项目 右键Repositories 选择Customize pemissions&#xff0…

SQL高级教程第三章

SQL CREATE DATABASE 语句 CREATE DATABASE 语句 CREATE DATABASE 用于创建数据库。 SQL CREATE DATABASE 语法 CREATE DATABASE database_name SQL CREATE DATABASE 实例 现在我们希望创建一个名为 "my_db" 的数据库。 我们使用下面的 CREATE DATABASE 语句&…

轻量应用服务器5m支持多少人访问?

​  轻量应用服务器5m支持多少人访问?对于网站而言&#xff0c;服务器的带宽肯定是越大越好&#xff0c;但对于用户的钱包则相反&#xff0c;服务器的价格高低与带宽大小、类型也有很大的关系&#xff0c;我们只有选择到合适的带宽才能将轻量应用服务器显得更有性价比&#…

DAY41:贪心算法(十)监控二叉树

文章目录 968.监控二叉树思路遍历顺序空节点处理情况列举 最开始的写法debug测试&#xff1a;travelsal的输出多了1 修改版二叉树注意点时间复杂度总结 968.监控二叉树 给定一个二叉树&#xff0c;我们在树的节点上安装摄像头。 节点上的每个摄影头都可以监视其父对象、自身及…