jvm 内存模型概述

2ddee8d86b054e71a48562b86c0c89c9.gif一、类加载子系统

 

1、类加载的过程:装载、链接、初始化,其中,链接又分为验证、准备和解析

装载:加载class文件

 

验证:确保字节流中包含信息符合当前虚拟机要求

 

准备:分配内存,设置初始值

 

解析:将变量从符号引用改为直接引用

 

初始化:执行类构造器方法

 

 

 

2、类加载器的分类

加载阶段使用到类加载器,类加载器分为:由C++实现的引导类加载器和由java实现的自定义加载器

 

自定义加载器又分为三层类加载器:拓展类加载器,应用程序类加载器和系统类加载器

 

 

 

①、引导类加载器:启动类加载器,将lib目录下,或-Xbootclasspasth参数指定路径存放的,java虚拟机能识别的类库加载进虚拟机;

 

②、拓展类加载器:将\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库加载进虚拟机;

 

③、系统类加载器:应用程序类加载器:负责加载用户类路径上所有的类库,可以直接在开发中使用这个类加载器;

 

④、自定义类加载器:用户自定义的类。

 

3、双亲委派机制

java虚拟机对class文件采用按需加载的方式,即在需要使用到类时,才加载对应的类到内存中,并且使用双亲委派机制的模式进行加载:

 

①:当一个类加载器收到了类加载的请求,不会立刻自己加载,而是将请求委托给父类的加载器去加载;

 

②、当父类加载器还存在父类加载器,则继续往上依次委托,最终的委托到最顶层的启动类加载器;

 

③、如果父类的加载器可以完成类加载器,则成功返回;如果父类加载器无法完成加载,子类加载器才会尝试着自己去加载。

 

这就是双亲委派机制的加载过程。

 

双亲委派机制的优势:

可以避免类的重复加载;

 

保护程序的安全,避免核心的api被篡改。

 

4、沙箱安全机制

java代码被限定在虚拟机特定的运行范围中,并且严格限制代码对本地资源的访问,通过这样来保护代码的的有效隔离性,防止本地系统造成破坏,这就是沙箱安全机制。

 

沙箱主要限制系统资源访问,例如:cpu、内存,文件系统、网络。不同级别的代码相对这些资源的访问的限制也可以是不一样的。

 

二、运行时数据区

1、虚拟机栈

每个线程在创建的时候,都会创建一个虚拟机栈,虚拟机栈是属于线程私有的。

 

 

 

a、栈帧(Stack Frame)

虚拟机栈中会存放着一个一个的栈帧,一个栈帧对应着一个方法,用于支持方法的调用和方法执行的数据结构;

 

虚拟机栈帧中存放着方法的局部变量表、操作数栈、动态链接和方法返回地址,在编译代码时,栈帧中需要多大的局部变量表和多深的操作数栈都已经确定好了。

 

①局部变量表:是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。注意:在mian()方法中,第一个表中的第一个位置的参数是args;

 

局部变量表存放了编译器可知的各种基本数据类型,对象引用和方法返回地址;

 

局部变量表以变量槽为最小单位,每个槽可以存放32位的长度,即long类型和doubule类型占俩个变量槽,而其他的基本数据类型占一个变量槽。

 

②操作数栈:用于保存计算过程中的中间结果,同时作为计算过程中变量的临时存放空间;

 

③动态链接:指向运行时常量池中该帧所属方法的引用;包含这个引用的目的是为了支持当前方法的代码能够实现动态链接,如:invokedynamic指令。

 

在java源文件被编译到字节文件中时,所有的变量和方法引用都作为符号引用保存在class文件的常量池里,程序运行时将其加载进方法区的运行时常量池中;

 

如描述一个方法调用了另外的其他方法时,就是  通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用 转为调用方法的直接引用。

 

④方法返回地址:存放该方法在寄存器中的值,即是该方法的指令地址,方便执行引擎在执行完该方法后,回到该方法对应的指令行号,这样才能继续执行下去。

 

2、程序计数器

程序计数器,又称pc寄存器,存储下一条要执行的指令的地址,每个线程都有专属的pc寄存器。

 

程序执行时,会不停的切换不同的线程进行执行,有些线程可能执行一般,就被停止执行,转而执行其他线程,这时候pc寄存器会记录下知道到的指令行号,等到线程获取到资源重新执行时,会依据pc寄存器中的指令,继续往下执行。

 

3、堆

 

 

堆由新生代和老年代组成

 

新生代

新生代由Eden区(伊甸园区)和俩个Survior(幸存区),Survior0,Survior1,新生代一般用来存放新创建的对象。

 

①Endn区:几乎所有的对象都在Eden区中创建,即Eden是大部分对象产生的地方;

 

创建的对象有部分存在的周期很短,有些对象的存在周期很长,当Eden区的内存满了时,会触发Minor GC 进行垃圾收集;

 

②Survior区: 幸存区 ,幸存区划分为俩个区Survior0和Surivor1即,幸存区0和幸存区1,在进行垃圾收集时,哪个区为空则为Survior0;一般都是俩个区互相替换成为Survior0;

 

Survior0 和Survior1俩个区的存储空间一般为1:8的比例,但实际大多数情况都达不到这个比例,可以使用-XX:SurviorRatio参数进行设置。

 

老年代

老年代一般用来存放生存周期较长的对象,当老年代的存储空间不足时,会触发Major GC或Full GC进行垃圾收集。

 

新生代和老年的存储空间比例为1:2,可以通过 -XX:NewRatio 参数进行设置。

 

垃圾收集

在堆中,有三个垃圾收集算法:Minor GC、Major GC 和 Full GC

 

①Minor GC

新生代垃圾收集,只是新生代(Eden、Survior0和Survior1)的垃圾收集。

 

触发机制:当新生代中的Eden区的空间不足时触发(注意:Survior区空间不足时不会主动触发,Survior区只会被动触发机制)进行垃圾收集。因为大多数java对象都具备朝生夕灭的特性,所以Minor GC触发的非常频繁,一般回收的速度也比较快。

 

收集过程:a、新生代中,对于每个对象都有一个引用计数器,当Eden区的空间满了只有,只有还被引用的对象能存活不被清理,并且会转移到Survior0区,对象的引用计数器增加1,代表这个对象存活的年龄增大一岁;

 

b、重复a步骤,将存活的对象复制到S0区,存活年龄增大,已存在在S0区的对象也相对应的增加存活年龄;

 

c、当Eden区和S0区空间满时,会将S0中的对象转移到S1中,存活的对象相对应的存活年龄,然后Eden和S0区会被清空,存活的对象全部在S1中,并且对象的存在着不一样的存活年龄。此时S0会变成意义上的S1(区中为空),S1会变成意义上的S0;如此反复,空的区为S1,对象存活的数据区为S0。

 

d、当不断进行Minor GC知道对象的存活年达到阈值(通过-XX:MaxTenuringThreshold设置,默认是15),则达到阈值年龄的对象,会判定为生命周期较长的对象,会被promote到老年代;不断的进行Minor GC,也会不断有对象被promote到老年代中。

 

TLAB:TLAB是一块为了解决线程安全问题所设置的存储空间,属于新生代的Ede区,TLAB内存空间非常小,仅占Eden的1%,不是所有的对象的实例都能在TLAB中成功分配内存,但JVM确实是以TLAB作为分配内存的首选。

 

堆空间是所有线程共享的,但Eden中的TLAB是线程私有的,解决线程的安全问题。

 

Major GC

老年代垃圾收集,只进行老年代的垃圾收集。

一个对象如果很大,那么会直接进入老年代中,即老年代存在着大对象和存活周期长的对象。

 

触发机制:老年代的空间不足时,会尝试触发Minor GC 进行新生代的垃圾收集,如果触发后空间还是不足,则触发Major GC;

 

Major GC的速度一般会比Minor GC的速度慢10倍以上,STW的时间更长,如果触发后依旧空间不住,则报OOm错误。

 

一把只有CMS GC 会有单独收集老年代的行为,很多时候,Major GC和 Full GC都是混淆这是用触发。

 

收集过程:一般Major GC 和 Full GC 同时触发,收集整个堆。

 

Full GC

整堆收集,收集整个java堆和方法区的垃圾。

 

触发机制:a、调用System.gc()时,系统会建议执行Full GC,但不必然执行;

 

b、老年代空间不足时;

 

c、方法区空间不足时;

 

d、通过Minor GC后进入老年代的平均大小大于老年代的可用内存;

 

e、有Eden区、Survior space0(From space) 区向Survior space(To space)区复制时,对象大小大于 To space的可用空间大小,则对象复制到老年代,但对象大小又大于老年代可用空间时触发。

 

Full GC是开发或调优中尽量避免的,这样暂停的时间会短一些

 

代码优化

堆不是分配对象存储的唯一选择,如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么可能被优化成栈上分配。

 

逃逸分析:分析一个对象的作用域,当一个对象在方法中定以后,对象只在方法内部使用,则认为没有发生逃逸;当一个对象定以后,它被外部方法所用(例如:return了变量或作为参数传递到了其他方法),则认为发生了逃逸。

 

栈上分配:没有发生逃逸的对象,可以分配到线程专属的栈上,随着方法执行的结束,栈空间也被移除,变量也被移除,无需进行GC。

 

代码优化(不发生逃逸分析的情况)

1、栈上分配;

 

2、同步省略:变量只有一个线程访问,取消其同步策略;

 

3、分离对象或标量替换

 

标量:指一个无法再分解成更小的数据的数据,如基本数据类型。

 

分离对象或标量替换就是将一个大的对象分解成多个标量存放在不连续的内存地址。

 

4、方法区 -- Metaspce 元空间

方法区和java对是一样的,是各个线程共享的区域,它用于存储已被加载类的信息,常量,静态变量,即使编译偶的代码等数据。

 

元空间的演进

 

 

5、本地方法栈

java虚拟机栈用于管理java方法的调用,而本地方法栈用于管理对本地方法的调用。

 

本地方法:java调用非java代码的接口,如操作系统或和某些硬件交换信息。

 

java应用对java外部的环境交互,这就是本地方法存在的原因。

 

当一个线程调用一个本地方法时,它就进入了一个新的并且不再受java虚拟机限制的世界,它和虚拟机拥有一个样的权限。

 

三、执行引擎

执行引擎负责将字节吗指令解释/编译成对应平台上的本地机器指令,即将高级语言翻译成机器语言。

 

java编译和执行的过程:

 

 

java为半编译半解释型语言,java在执行代码的时候,会将解释和编译执行二者结合起来进行。

 

执行引擎获取到后,将由javac将源码编译成字节码.class文件后,在运行解释器最终转换为机器码(解释器)。

 

解释器:java中,对字节码采用逐行解释的方式执行(边解释边执行),将每个字节码文件中的内容翻译对应机器平台的机器语言。

 

JTI编译器:虚拟机将源代码直接编译成和本地机器平台相关的机器语言。

 

解释器和JIT并存

 

 

即使编译的触发:热点探测

名词解析:1、热点代码:被调用执行频率高的代码被称为热点代码;

 

​ 2、方法调用计数器:统计方法被调用的次数;

 

​ 3、回边计数器:统计循环执行体执行的循环次数。

 

目前HotSpot的热点探测是基于计数器的的热点探测;

 

热点探测:当一个方法的方法调用计数器或回边计数器的次数达到阈值时,会出发即时编译,将代码运行从解释器执行改为即使编译执行。

 

​ 方法计数器不是一直在增加的,在一段时间内,方法的调用次数一直没有变(半衰周期),这个方法的方法调用计数器就会减少一半,这个过程称为方法计数器热度的衰减。

 

为什么即使编译和解释器并存

JIT编译器要发挥作用,,需要将代码全部编译成本地指令,需要一定的时间(但编译后的代码执行效率高),所以在程序刚启动时,需要用解释器进行逐行编译成机器指令。所以,jvm对这种俩种是进行了取长补短。

 

四、对象创建

对象创

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

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

相关文章

计算机算法分析与设计(23)---二分搜索算法(C++)

文章目录 1. 算法介绍2. 代码编写 1. 算法介绍 1. 二分搜索(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search&#xf…

十. Linux关机重启命令与Vim编辑的使用

关机重启命令 shutdown命令 其他关机命令 其他重启命令 系统运行级别 系统默认运行级别与查询 退出登录命令logout 文本编辑器Vim Vim简介 没有菜单,只有命令Vim工作模式 Vim常用命令 插入命令 定位命令 删除命令 复制和剪切命令 替换和取消命令 搜索和搜索替换命令 保存和退出…

Clickhouse初认识

技术主题-clickhouse 一什么是clickHouse 1)本质上就是一款数据库管理系统,能提供海量数据的存储和检索 2)基于列存储,数据是按照列进行存储的(数据格式一样,方便进行压缩) 3)具备…

【Rust】快速教程——闭包与生命周期

前言 你怎么向天生的瞎子说清颜色?怎么用手势向天生的聋子描述声音? 鲜花就在眼前,雷鸣就在头顶,对他们来说却都毫无意义 眼睛看不到,鼻子可以嗅闻花香,耳朵听不见,手指可以触碰窗纸的震动。 犯…

【C语言】数组下标为啥从0开始?下标越界访问一定报错吗?

本篇文章目录 0. 相关文章1. 下标从0开始问题2. 数组下标越界不报错问题 0. 相关文章 指针与指针变量数组名不是首元素地址的的2个例外拨开指针和数组名之间的迷雾 1. 下标从0开始问题 原因是:数组下标访问本质是“指针解引用操作”,而指针又是地址&am…

C++之map容器

C之map容器 map构造和赋值 #include<iostream> #include<string> using namespace std; #include<map>void printMap(map<int,int>&m) {for (map<int,int>::iterator it m.begin();it ! m.end();it){//cout <<"key is: "&l…

LeetCode994.腐烂的橘子

看完题我觉得这不是和上一道岛屿的题一样简单嘛&#xff0c;然后写了将近2个小时才写出来&#xff0c;我的思路就是&#xff0c;用check()先对grid检查一下&#xff0c;是否有以下情况&#xff1a; &#xff08;如果有1的周围都是空&#xff0c;则这个位置用不腐烂&#xff0c;…

[Docker]六.Docker自动部署nodejs以及golang项目

一.自动部署nodejs 1.创建node项目相关文件 app.js代码如下: var express require(express);var appexpress();app.get(/,function(req,res){res.send(首页update); }) app.get(/news,function(req,res){res.send(首页); })//docker做端口映射的时候不要指定ip app.listen(30…

2.2 调用星火大模型的API

调用星火大模型的API 1 申请API调用权限&#xff1a;2 调用原生星火 API3 统一API调用方式 项目仓库地址&#xff1a;https://github.com/datawhalechina/llm-universe 讯飞星火认知大模型&#xff0c;由科大讯飞于2023年5月推出的中文大模型&#xff0c;也是国内大模型的代表…

【原创】java+swing+mysql鲜花购物商城设计与实现

前言&#xff1a; 本文主要介绍了鲜花购物商城的设计与实现。首先&#xff0c;通过市场需求&#xff0c;我们确定了鲜花商场的功能&#xff0c;通常的商城一般都是B/S架构&#xff0c;然而我们今天要用javaswing去开发一个C/S架构的鲜花商城&#xff0c;利用开发技术和工具&am…

vue使用navigator.mediaDevices.getUserMedia调用相机功能

目录 前言&#xff1a; API&#xff1a; API简单示例&#xff1a; 拍照功能 实现效果&#xff1a; 前言&#xff1a; 本文将介绍Vue中如何使用navigator.mediaDevices.getUserMedia调用相机功能&#xff0c;实现拍照使用实例&#xff0c;需要的朋友可以参考一下。 注意…

十三、Docker的安装

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

大师学SwiftUI第18章Part1 - 图片选择器和相机

如今&#xff0c;个人设备主要用于处理图片、视频和声音&#xff0c;苹果的设备也不例外。SwiftUI可以通过​​Image​​视图显示图片&#xff0c;但需要其它框架的支持来处理图片、在屏幕上展示视频或是播放声音。本章中我们将展示Apple所提供的这类工具。 图片选择器 Swift…

[Vue3] pinia状态管理

文章目录 1.pinia的介绍2.pinia的配置3.state状态管理3.1 state的基本使用3.2 state的访问 4.getters 1.pinia的介绍 Pinia 是 Vue 的专属状态管理库&#xff0c;它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话&#xff0c;你可能会认为可以通过一行简单的 export …

电子商务、搜索引擎

电子商务 域名 网络服务 网络樱肖 搜索引擎优化

接口自动化测试中解决接口间数据依赖

在实际的测试工作中&#xff0c;在做接口自动化测试时往往会遇到接口间数据依赖问题&#xff0c;即API_03的请求参数来源于API_02的响应数据&#xff0c;API_02的请求参数又来源于API_01的响应数据。 因此通过自动化方式测试API_03接口时&#xff0c;需要预先请求API_02接口&a…

【LeetCode刷题日志】225.用队列实现栈

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;C/C领域新星创作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;LeetCode 刷题日志&#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论区留言指正&#xff0c;…

MFC 对话框

目录 一、对话款基本认识 二、对话框项目创建 三、控件操作 四、对话框创建和显示 模态对话框 非模态对话框 五、动态创建按钮 六、访问控件 控件添加控制变量 访问对话框 操作对话框 SendMessage() 七、对话框伸缩功能实现 八、对话框小项目-逃跑按钮 九、小项…

文章分类列表进行查询(实体类日期格式设置)

categoryController GetMappingpublic Result<List<Category>> list(){List<Category> cs categoryService.list();return Result.success(cs);} categoryService //列表查询List<Category> list(); categoryServiceImpl Overridepublic List<Cat…

科研学习|科研软件——面板数据、截面数据、时间序列数据的区别是什么?

一、数据采集方式不同 面板数据是通过在多个时间点上对同一组体进行观测而获得的数据。面板数据可以是横向面板数据&#xff0c;即对同一时间点上不同个体的观测&#xff0c;也可以是纵向面板数据&#xff0c;即对同一个体在不同时间点上的观测。采集面板数据需要跟踪相同的个体…