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

JavaEE:JVM

基本介绍

JVM:Java虚拟机,用于解释执行Java字节码

jdk:Java开发工具包

jre:Java运行时环境

C++语言将写入的程序直接编译成二进制的机器语言,而java不想重新编译,希望能直接执行。Java先通过javac把.java文件转成.class文件,.class文件是字节码文件,包含Java字节码,然后Java把这个字节码文件在某个具体的平台上执行。此时再通过jvm把上述的字节码转成对应的CPU能识别的机器指令

当前主流的JVM:HotSpot VM


JVM中的内存区域划分

JVM其实也是一个进程,就是在任务管理器中能看到的Java进程

进程运行的过程中,要从操作系统申请一些资源(典型资源:内存),申请到的内存空间可以支撑后续Java程序的执行。

比如:在Java中定义变量,就会申请内存,这里的申请就是由jvm完成的

而jvm申请的这一块内存还会根据实际的用途划分出不同的空间(区域划分)

1.堆:代码中new出来的对象,对象中持有的非静态成员变量都是在堆里(只有一份)

2.栈:本地方法栈包含了方法调用关系和局部变量,虚拟机栈记录了Java代码的调用关系,Java代码的局部变量(一般提到的栈指的是虚拟机栈)(可以有n份,n与线程相关)

这里的堆和栈和数据结构里的不一样

这里的堆和栈都是内存区域,而数据结构的堆是一颗二叉树,栈是后进先出的数据结构

3.程序计数器:空间比较小,存储下一条要执行的Java指令的地址(有n份)

x86的CPU也有一个类似的寄存器:eip

4.元数据区:保存类的信息和方法的信息 (只有1份)

类的信息:类的名称,继承哪个类,实现的接口;有什么属性,属性名字,属性类型,权限;有什么方法,方法名字,方法参数,权限等等

“元数据(meta data)”:往往指一些描述性质或者辅助性质的属性


笔试题

class Test{private int n;private static int m;
}main(){Test t = new Test();
}

上述代码里的t, n, m各自处于jvm哪个区域

t是一个局部变量(引用类型),这个变量在栈上

n是Test的成员变量,处于堆上

m是static修饰的变量,称为类属性,存在类对象中,也属于元数据区


JVM的类加载机制

类加载:Java进程运行的时候需要把.class文件从硬盘读取到内存并进行一系列的校验解析的过程

过程(5个步骤)

1.加载:把硬盘上的.class文件找到打开文件,读取文件内容(读到的是二进制数据)

如何查找对应的文件?双亲委派模型(一种查找策略)

2.验证:确保读到的文件是合法的.class文件(验证依据:Java的虚拟机规范)

3.准备:给类对象申请内存空间,申请到的内存空间里面的默认值是0

4.解析:针对类中字符串常量进行处理,将常量池中的符号替换成直接引用的过程

class Test{private String s = "hello";
}

 

在代码中我们知道s相当于包含了"hello"字符串常量的地址,但是在文件中是不存在"地址"这样的概念的。地址是内存的地址,硬盘里没有地址。

虽然没有地址,但是我们可以存储一个类似于地址的偏移量

把hello字符串的开头到文件开头就是一个偏移量

此处文件中填充给s的hello的偏移量就认为是符号引用,接下来把.class文件加载到内存中,先把"hello"这个字符串加载到内存中,此时“hello”就有地址了,s里面的值就可以替换成当前“hello”真实的地址了,可以直接引用这个地址了

5.初始化:针对类对象完成后续的初始化(要执行代码块的逻辑,甚至会触发父类的加载)


双亲委派模型(重点)

JVM中的类加载操作有一个专门的模块:类加载器

作用:给定全限定类名,也就是带有包名的类名,比如java.lang.String就是一个全限定类名,能找到.class文件

默认有三个

BootstrapClassLoader:负责查找标准库的目录

ExtensionClassLoader:负责查找扩展库的目录

ApplicationClassLoader:负责查找当前项目的代码目录以及第三方库的目录

上述三个类加载器存在父子关系,这个父子关系类似于二叉树,有一个指针parent,指向自己的父类加载器

双亲委派模型的工作过程:

1.从ApplicationClassLoader作为入口,先开始工作

2.ApplicationClassLoader不会立即搜索自己负责的目录,会把搜索的任务交给自己的父亲

3.代码进入到ExtensionClassLoader的范畴,ExtensionClassLoader也不会立即搜索自己负责的目录,会把搜索任务交给父亲

4.BoostrapClassLoader没有父亲,没办法推脱搜索任务了,才会真正搜索自己负责的标准库目录。通过全限定类名,尝试在标准库目录中找到符合要求的.class文件

找到了就直接进入打开文件和读文件的流程;如果没到找,返回给孩子类加载器,继续尝试加载

5.ExtensionClassLoader收到交回的任务后,在自己负责的扩展库目录搜索,找到了进入后续流程,没找到再丢给自己孩子

6.ApplicationClassLoader收到交回的任务后,自己进行搜索负责的目录。再找不到就抛出ClassNotFoundException 异常

上述执行顺序的好处:

1)确保几个类加载器之间的优先级

2)用户自定义的类不会被jvm加载,可以防止自定义类不小心和标准库中的类名字重复


JVM的垃圾回收机制(GC机制)

基本情况

这个机制不需要程序员手动释放内存。程序回自动判断某个内存是否会继续使用,如果内存后续不用了,就会自动释放掉。

垃圾回收中一个重要问题:STW(stop the world)问题——触发垃圾回收的时候,可能会使当前程序的其他业务逻辑被暂停

垃圾回收内存的话,那内存里面几个区域里面情况如何?

1)程序计数器 -- 不需要GC

2)栈 -- 不需要GC,因为局部变量在代码块执行结束之后自动销毁

3)元数据区/方法区 -- 不需要GC,因为一般都是涉及类加载而不是类卸载

4)堆 -- GC的主要工作区域

所以,垃圾回收回收内存,不如说是回收对象(对象也是回收的单位)


工作机制

1.识别出垃圾

判定哪些对象不再使用,哪些对象还在使用

在Java中的对象一定要通过引用的方式来使用,除非匿名对象。如果一个对象没有任何引用指向它,就可以认为无法被代码引用,就可以作为垃圾了

void func(){Test t = new Test();t.do();
}

这里通过new Test在堆上创建了对象,与此同时在栈上也存储下这个局部变量

当执行到 “}” 的时候,t这个局部变量在栈中自动销毁。上面的new Test()对象就没有引用指向它了。此时这个对象就成为了垃圾

如果代码复杂一点呢?

Test t1 = new Test();
Test t2 = t1;
t3 = t2;
t4 = t3;

此时会有很多引用指向new Test同一个对象,需要确保所有的引用都销毁了才能把Test对象视为垃圾。如果代码再复杂,每个引用的生命周期各不相同,那怎么办呢?

解决办法:

1)引用计数:给每个对象安排一个额外的空间,空间里要保存当前这个对象有几个引用

每次有一个引用指向这个对象,引用计数就+1,制空或者删除一个引用,引用计数就-1

此时有专门的扫描线程去获取当前每个对象的引用计数情况,如果发现对象的引用计数为0,说明这个对象可以被释放了

这个方法虽然没有在JVM中使用,但是广泛应用于其他语言的垃圾回收机制中,比如python和PHP

问题一:每个对象分配到的计数器消耗了额外的内存空间,对象数目一多空间资源容易不足

问题二:引用计数可能会产生“循环引用的问题”

此时两个对象,引用计数都不是0,不能被GC回收掉,但是这两个对象又无法使用 -- 类似于死锁


2)可达性分析(JVM用的是这个)

本质上用时间换空间。在写代码的时候会定义很多变量,就可以从这些变量作为起点,尝试进行遍历(沿着这些变量中持有的引用类型的成员,再进一步地往下进行访问),所有能被访问的对象就不是垃圾了,剩下的遍历一圈也访问不到的对象就是垃圾

虽然这个代码中只有一个root的引用,但是7个结点的对象都是可达的。JVM中存在扫描线程,会尽可能多的去遍历访问对象

如果root.right = null的话,a跟c之间就会断开,那么按照上述方法遍历的操作就无法访问到c和f了,此时c和f节点对象就不可达,不可达就变成垃圾了


2.把标记为垃圾的对象的内存空间进行释放

释放方式

1)标记 - 清除

把标记成垃圾的对象直接释放掉(一般不使用)

产生的问题:内存碎片 -- 小的但是离散的空闲内存空间

会导致后续的内存申请失败。因为我们的内存申请时一次性申请一个连续的空间,比如我们申请1M的内存空间,此时的1M字节都是连续的

如果有很多内存碎片就可能导致空闲空间总和超过1MB,但是没有比1MB大的连续空间,申请就会失败


2)复制算法

核心是不直接释放内存,而是把内存划分成为两半

把不是垃圾的对象复制到内存的另一半里,接下来就把左侧的空间(原来垃圾存在的空间)整体释放掉

比如我们要删掉对象2和4,我们会把不需要删除的1和3复制一份到右半边内存

然后把左半边全删掉

优点:规避内存碎片问题

缺点:1)总的可用内存变少;2)如果每次要复制的对象很多,复制的开销很大(所以这个算法适用情况:当前这轮GC中要删掉的对象很多,存活的对象很少)


3)标记 - 整理

类似顺序表删除中间的元素(搬运思想)

比如下面要删除1,3,6

接着把2,4,5,7,8往前搬运

优点:解决内存碎片问题,不需要过多浪费内存空间

缺点:复制开销很大


4)JVM采用的综合方案:分代回收(重点)

引入概念:对象的年龄(初始年龄为0)

JVM中有专门的线程负责周期性扫描或释放。一个对象如果被线程扫描了一次,发现是可达了,该对象的年龄+1

JVM会根据对象年龄的差异,把整个堆内存分成两个大的部分,分别为新生代(年龄小的对象)和老年代(年龄大的对象)

具体流程:复制算法+标记 - 整理

a)当代码中new处理一个新的对象,这个对象就被放在伊甸区

一个经验规律:大部分伊甸区的对象是朝生夕死的,活不过第一轮GC

b)第一轮GC扫描之后,少数幸存的对象就会通过复制算法拷贝到生存区,后续GC扫描线程继续扫描,生存区中大部分对象也会在扫描中被标记为垃圾,少数存活的会被拷贝到另一半的生存区中每经历一轮扫描,生存的对象年龄+1

c)如果这个对象在生存区中经过若干轮GC之后还存活着,JVM会认为这个对象的生命周期很长,就会将其从生存区拷贝到老年代

d)老年代的对象也要参与扫描,但是被扫描的频率大大降低

e)对象在老年代寄掉了,JVM就将其释放了

常使用的垃圾收集器:GMS, G1和ZGC

相关文章:

JavaEE:JVM

基本介绍 JVM:Java虚拟机,用于解释执行Java字节码 jdk:Java开发工具包 jre:Java运行时环境 C语言将写入的程序直接编译成二进制的机器语言,而java不想重新编译,希望能直接执行。Java先通过javac把.java…...

Linux基础|线程池Part.1|线程池的定义和运行逻辑

线程池的定义和运行逻辑 多线程的问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。 那么一个很自然的想法就出现了…...

蓝队面试经验总结

Sql注入 1、sql注入漏洞原理 开发者没有在网页传参点做好过滤,导致恶意 sql 语句拼接到数据库进行执行 2、sql注入分类 联合注入 、布尔盲注 、时间盲注 、堆叠注入 、宽字节注入 、报错注入 3、堆叠注入原理 在 mysql 中,分号 代表一个查询语句的…...

MySQL命令分类与大纲

一、数据库管理 创建与删除数据库 CREATE DATABASE:创建新数据库DROP DATABASE:删除已存在的数据库ALTER DATABASE:修改数据库属性 切换与查看数据库 USE:选择当前工作数据库SHOW DATABASES:列出所有可用数据库 二、…...

windows编译xlnt,获取Excel表里的数据

用git拉取项目 这个文件是空的 要用git拉下来&#xff0c;使用终端编译xlnt库 点击解决方案 运行生成 然后新建项目&#xff0c;配置好库&#xff0c; #include <iostream> #include <xlnt/xlnt.hpp>int main() {// 打开 Excel 文件xlnt::workbook workbook;workb…...

c#字段和属性的区别

在C#中&#xff0c;字段&#xff08;fields&#xff09;和属性&#xff08;properties&#xff09;都是类的成员&#xff0c;它们提供了类存储数据的方式&#xff0c;但它们在用途和功能上有着明显的区别。 字段 字段通常用来存储类或结构的状态信息。字段是类的数据成员&…...

微软正式发布Copilot for Security

微软公司近日宣布&#xff0c;其备受期待的安全自动化解决方案——Copilot for Security现已全面上市&#xff0c;面向全球用户开放。这一创新工具的推出标志着微软在提升企业安全防护能力方面迈出了重要一步&#xff0c;同时也为安全专业人士提供了强大的支持。 Copilot for …...

AI大模型日报#0416:李飞飞《2024年人工智能指数报告》、Sora加入Adobe、李彦宏聊百度大模型之路

​导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 刚刚&#xff0c;李飞飞团队发布《2024年人工智能指数报告》&#xff1a;10大趋势&#xff0c;揭示AI大模型的“喜”与“忧” 摘…...

OpenCV轻松入门(八)——图片卷积

对图像和滤波矩阵进行逐个元素相乘再求和的操作就相当于将一个二维的函数移动到另一个二维函数的所有位置&#xff0c;这个操作就叫卷积。 卷积需要4个嵌套循环&#xff0c;所以它并不快&#xff0c;除非我们使用很小的卷积核。这里一般使用3x3或者5x5 图像滤波 图像滤波是尽…...

鸿蒙HarmonyOS开发规范-完善中

代码规范 所有文件&#xff0c;包括自动生成的编译文件package.json都要格式化&#xff08;IDE快捷键CtrlAltL&#xff09;&#xff1b;函数命名&#xff0c;C大驼峰&#xff0c;TS、JS小驼峰&#xff0c;函数命名注意动宾结构&#xff1b;静态常量需使用全大写&#xff0c;文…...

神经网络压缩图像

简介 典型的压缩管道由四个组件组成&#xff1a; 编码&#xff1a;输入图像 x x x通过编码器函数 ε \varepsilon ε&#xff0c;将其转换为潜在表示 z z z。 量化&#xff1a;截断 z z z以丢弃一些不重要的信息 熵编码&#xff1a;使用某种形式的熵编码&#xff08;例如&…...

Catagory(rt)

继承(IMP融合):支持super命令码;继承推荐重写 分类(IMP替换):不支持super命令码;分类推荐组合 //替换(原来没了/破坏掉原来IMP/分类(替换特性)) 情况1: 自封装(组件化)开源库>分类推荐组合 情况2:逆向分析> 有意替换>分类IMP替换 #import "CatagoryViewContro…...

Games104 现代游戏引擎3

Sprite Animation 序列帧动画 自由度&#xff08;degrees of freedom&#xff0c;DoF&#xff09;对于刚体而言描述它的运动需要3个位移3个旋转&#xff0c;一共6个自由度 顶点动画&#xff08;per-vertex animation&#xff09;利用网格的顶点来控制运动。此时网格上的每个顶…...

【云计算】混合云分类

《混合云》系列&#xff0c;共包含以下 3 篇文章&#xff1a; 【云计算】混合云概述【云计算】混合云分类【云计算】混合云组成、应用场景、风险挑战 &#x1f60a; 如果您觉得这篇文章有用 ✔️ 的话&#xff0c;请给博主一个一键三连 &#x1f680;&#x1f680;&#x1f68…...

探索分布式系统监控zabbix------------自动发现与自动注册

目录 一、部署 zabbix 服务端 二、部署 zabbix 客户端 2.1环境准备 2.2服务端和客户端都配置时间同步 &#xff08;ntp&#xff09; 2.2.1服务端zbx-server 2.2.2服务端zabbix-agent01客户端 2.3客户端配置时区&#xff0c;与服务器保持一致 2.4设置 zabbix 的下载源&…...

权限管理Ranger详解

文章目录 一、Ranger概述与安装1、Ranger概述1.1 Ranger介绍1.2 Ranger的目标1.3 Ranger支持的框架1.4 Ranger的架构1.5 Ranger的工作原理 2、Ranger安装2.1 创建系统用户和Kerberos主体2.2 数据库环境准备2.3 安装RangerAdmin2.4 启动RangerAdmin 二、Ranger简单使用1、安装 R…...

WPF Extended.Wpf.Toolkit 加载界面

1、NuGet 中安装 Extended.Wpf.Toolkit 。 2、在MainWindow.xaml中添加xmlns:tk"http://schemas.xceed.com/wpf/xaml/toolkit" 。 MainWindow.xaml 代码如下。 <Window x:Class"WPF_Extended_Wpf_Toolkit_Loading.MainWindow" xmlns"ht…...

【切换网络连接后】VMware虚拟机网络配置【局域网通信】

初次安装Linux虚拟机以及切换网络都需要配置虚拟机网络&#xff0c; 从而使得win主机内通过远程连接工具能够连接该虚拟机&#xff0c; 而不是在虚拟机内操作。 本片文章你将了解到网络切换后如何配置虚拟机网络的一些基础操作&#xff0c;以及局域网通信的一些基础知识。 …...

革新鞋服零售:数据驱动的智能商品管理 解锁库存优化与高效增长

国内鞋服零售企业经过多年的发展&#xff0c;已经形成诸多家喻户晓的品牌&#xff0c;但近年来一些企业的库存问题也时常显现&#xff0c;高库存不仅困扰着品牌商&#xff0c;也使一些多年合作良好的经销商深受其害&#xff0c;当下的订货会制度在初期帮助企业解决了盲目生产的…...

word文件的创建时间和修改时间可以更改吗?答案是肯定的 文件属性修改的方法

一&#xff0c;引言 在日常生活和工作中&#xff0c;我们经常需要处理各种Word文件。有时&#xff0c;由于某些原因&#xff0c;我们可能需要更改Word文件的创建时间和修改时间。虽然这听起来可能有些复杂&#xff0c;但实际上&#xff0c;通过一些简单的方法和工具&#xff0…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...