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

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

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

相关文章

02 - ArcGIS For JavaScript-矢量数据的符号化处理(Symbol)

文章目录 综述Symbol的分类Point的符号化Point符号化为二维几何:Point位图符号化:Point的三维结合符号化Point 符号化为GLTF模型 PolylineSymbol-线符号化基本样式管道样式墙体样式条带样式方管样式 PolygonSymbol-面符号化水面效果拉伸效果填充效果 Mes…

外面收费的彩虹自助下单系统模板

搭建教程 下载之后上传到template文件夹里面 注意带上里面的文件夹 然后去后台替换就行 源码免费下载地址抄笔记 (chaobiji.cn)

PLSQL中文乱码问题 + EZDML导入数据库模型乱码

PLSQL中文乱码问题 EZDML导入数据库模型乱码 查询数据库字符集 select userenv(language) from dual;查询本地字符集编码 select * from V$NLS_PARAMETERS;理论上 数据库字符集 跟 本地字符集编码 是一致的 本地字符集编码需要拼接字段值 NLS_LANGUAGE NLS_TERRITORY NLS…

项目7-音乐播放器2(上传音乐+查询音乐+拦截器)

0.加入拦截器 之后就不用对用户是否登录进行判断了 0.1 定义拦截器 0.2 注册拦截器 生效 1.上传音乐的接口设计 请求: { post, /music/upload {singer,MultipartFile file}, } 响应: { "status": 0, "message&…

免费的 ChatGPT、GPTs、AI绘画(国内版)

🔥博客主页:白云如幻❤️感谢大家点赞👍收藏⭐评论✍️ ChatGPT3.5、GPT4.0、GPTs、AI绘画相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚…

2.4G漂移小车电子方案 酷得智能科技

漂移高速遥控车是一种专门设计用于执行高速漂移动作的遥控车模型。以下是一些关于漂移高速遥控车的功能介绍: 1、高速性能:漂移车通常配备有强力的电机和电池,以便在保持高速的同时进行漂移动作。 2、漂移能力:漂移车的轮胎和悬挂…

计算机网络:MAC地址 IP地址 ARP协议

计算机网络:MAC地址 & IP地址 & ARP协议 MAC地址IP地址ARP协议 MAC地址 如果两台主机通过一条链路通信,它们不需要使用地址就可以通信,因为连接在信道上的主机只有他们两个。换句话说,使用点对点信道的数据链路层不需要使…

SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测

SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现POA-TCN-BiGRU-Attention鹈鹕算法优化时间卷积双向门控循环单元注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考…

Proxyman Premium for Mac v5.1.1激活版:卓越的网络调试与分析工具

Proxyman Premium for Mac是一款功能强大的网络调试与分析工具,专为开发人员和测试人员精心打造。它集多种功能于一身,为用户提供了全面、高效的网络开发体验。 Proxyman Premium for Mac v5.1.1激活版下载 作为一款跨平台代理工具,Proxyman …

# RAG | Langchain # Langchain RAG:打造Markdown文件的结构化分割解决方案

【文章简介】 在信息技术的现代背景下,高效地处理和分析文本数据对于知识获取和决策支持至关重要。Markdown文件因其易读性和高效性,在文档编写和知识共享中占据了重要地位。然而,传统的文本处理方法往往忽视了Markdown的结构化特性&#xff…

WIN7用上最新版Chrome

1.下载WIN10最新版Chrome的离线安装包 谷歌浏览器 Chrome 最新版离线安装包下载地址 v123.0.6312.123 - 每日自动更新 | 异次元软件 文件名称:123.0.6312.123_chrome_installer.exe。 123.0.6312.123_chrome_installer.exe 文件右键解压缩得到 chrome.7z&#x…

Elasticsearch:下载、启动和账号密码登录

因为我的电脑是 window,以下都是以 window 环境举例。 一、下载 Elasticsearch 是使用 java 开发的,且 7.8 版本的 ES 需要 JDK 版本 1.8 以上,安装前注意java环境的准备。 官网地址:https://www.elastic.co/cn/ 下载地址&#xf…

第十五届蓝桥杯题解-好数

题目大意&#xff1a;一个数的低位为奇数&#xff0c;次低位为偶数&#xff0c;以此类推的数成为好数&#xff0c;例如&#xff1a;1&#xff0c;3&#xff0c;5&#xff0c;7&#xff0c;9 给定一个n&#xff0c;求1-n所有好数的个数&#xff0c;n<1e7 思路&#xff1a;一…

Python 数学应用(四)

原文&#xff1a;zh.annas-archive.org/md5/123a7612a4e578f6816d36f968cfec22 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十一章&#xff1a;其他主题 在本章中&#xff0c;我们将讨论一些在本书前几章中没有涉及的主题。这些主题大多涉及不同的计算方式以及优…

Python也可以合并和拆分PDF,批量高效!

PDF是最方便的文档格式&#xff0c;可以在任何设备原样且无损的打开&#xff0c;但因为PDF不可编辑&#xff0c;所以很难去拆分合并。 知乎上也有人问&#xff0c;如何对PDF进行合并和拆分&#xff1f; 看很多回答推荐了各种PDF编辑器或者网站&#xff0c;确实方法比较多。 …

C++学习————第六天 (运算符重载 const成员 取地址)

这一篇我们来补齐上一天的 留下的三个默认成员函数 //上一天内容 &#xff1a; nullhttps://blog.csdn.net/island1314/article/details/137371086?spm1001.2014.3001.5502 1、重载 1.1 运算符重载 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊…

AUTOCAD输出或打印PDF文件时,如何将图形居中且布满图纸?

AUTOCAD输出或打印PDF文件时,如何将图形居中且布满图纸? 如下图所示,我们打开一份DWG格式的图纸文件,然后点击上方的“打印“图标, 如下图所示, 打印机/绘图仪这里选择“DWG To PDF“; 图纸尺寸:这里以普通的A4纸为例进行说明; 打印比例选择“布满图纸“; 打印偏移…

uniapp 组件传值

uniapp 组件传值 父传子子传父 uniapp 组件传值 父传子 在uniapp中&#xff0c;组件传值主要通过props进行。以下是一个简单的例子&#xff1a; 首先&#xff0c;创建一个组件MyComponent.vue&#xff1a; <template><view><text>{{ message }}</tex…

计算机网络(六)应用层

应用层 基本概念 服务器端&#xff08;Server&#xff09;&#xff1a; 服务器是网络中提供服务的计算机或软件程序。服务器通常具有更高的性能、更大的存储空间和更高的带宽&#xff0c;用于提供各种服务&#xff0c;如文件存储、数据库管理、Web托管、电子邮件传递等。服务…

Redis 缓存预热、预热数据选取策略、缓存保温、性能边界

缓存预热 热点数据预热&#xff1a;根据业务分析或统计数据&#xff0c;确定热点数据&#xff08;经常被访问的数据&#xff09;&#xff0c;并将其提前加载到Redis缓存中。可以根据访问频率、访问量或其他业务指标来确定热点数据。定时预热&#xff1a;可以设置定时任务&…