JVM相关概念

news2024/11/24 8:41:51

16df1747c4d0485494930259a6a7b3f1.jpgJVM,全程Java Virtual Machine,是java虚拟机的意思!

 

是一个类似计算机的存在,是在计算机上模拟真实计算机运行的平台,它代替Java代码和各种计算机设备之间的交互!

Java程序把代码翻译成字节码交给虚拟机,虚拟机会将其解释成设备能识别的机器指令交给设备,

是一个中间层的概念!

 

相关概念

JRE/JDK/JVM 三者之间的关系

JDK:是Java开发工具包,开发者用起进行编译、调试,他本身也是一个Java程序

JRE:是Java运行环境,所有Java代码必须在jre环境内执行

JVM:是JRE的一部分,可跨平台

 

JVM内存结构

 

 

上面只是JVM的一种规范模型,具体每个模块都是啥意思,JDK1.7,1.8又是怎么实现的,下面会细说

 

内存概念模型

堆:存储各实例对象,属于线程共享

 

 

方法区:存储已被虚拟机加载的类信息、常量(静态常量池、运行时常量池)、即时编译器编译后的代码等数据,属于线程共享。

类信息:类的版本、字段、方法、接口和父类等信息

运行时常量池:存储的是类加载时生成的直接引用等信息。

静态常量池:主要存储的是字面量,以及符号引用等信息,也包括了我们说的字符串常量池

 

虚拟机栈:由一个一个的栈桢组成,每个Java方法从运行到结束都意味着一个栈桢从入栈到出栈的过程(这对方法递归的理解有所帮助),栈桢存储的是:局部变量表、操作数栈、动态链接、方法出口等信息 ,属于线程私有。

 

本地方法栈:和虚拟机栈功能类似,只不过他适用于Java调用一些native方法,属于线程私有。

比如 System.currentTimeMillis();

native 方法是 Java 中声明,由操作系统中具体方法实现

 

程序计数器:每个形成都有一个自己的程序计数器,记录的是下一条需要执行的字节码指令,也就是说记录了程序该走哪一步,线程停止程序停在了哪一步,下一次唤醒应该从哪一步走起;分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成

属于线程私有。

我们知道Java并不能直接执行,他需要被编译成JVM指令,然后在虚拟机中被调用给到机器执行,但其实这些指令也不能直接交给CPU去执行,他们需要被解释器解释成一个一个的机器码然后交给CPU去执行,所以计数器记录的也就是一条条指令的地址!

比如下面例子中的左侧是JVM指令,右侧是相应的源代码。

 

0: getstatic #20 // PrintStream out = System.out;

3: astore_1 // --

4: aload_1 // out.println(1);

5: iconst_1 // --

6: invokevirtual #26 // --

9: aload_1 // out.println(2);

10: iconst_2 // --

11: invokevirtual #26 // --

14: aload_1 // out.println(3);

15: iconst_3 // --

16: invokevirtual #26 // --

19: aload_1 // out.println(4);

20: iconst_4 // --

21: invokevirtual #26 // --

24: aload_1 // out.println(5);

25: iconst_5 // --

26: invokevirtual #26 // --

29: return

执行流程加上程序计数器后的样子

比如拿到了第一条getstatic指令,交给了解释器,解释器把他变成机器码,

然后再交给CPU运行,但是在与此同时,他就会把下一条指令即下面的astore_1

指令的地址即把3放入程序计数器。

所以等第一条指令执行完了以后,解释器就会到程序计数器里去取下一条指令,

根据地址3再找到下调指令astore_1,然后再重复刚才的过程。

当然,在执行3这条指令的时候,再把3的下一条即例子中的4存入程序计数器。

总之,他记录了下一个JVM的指令地址。

所以,如果没有程序计数器,他就不知道接下来该执行哪条命令了,这是程序计数器的基本作用。

 

现在来说下不同产品对JVM内存模型的不同实现

这里主要区别我觉得是方法区的实现

在HotSpot虚拟机,就会常常提到 永久代,这个词。HotSpot虚拟机在 JDK8前用永久代实现了方法区,而很多其他厂商的虚拟机其实是没有永久代的概念的。在JDK8中,已经用元空间来替代了永久代作为方法区的实现了,然后在JDK1.7已经对元空间做了变动,已经把 常量池 迁移到了堆空间进行存储!1.8在这一基础上彻底废弃了永久代,将这一概念变成了元空间,并且直接放到了内存进行存储!

 

垃圾回收:

什么是垃圾

没有用的对象就是垃圾,那问题就是如何判断没有被引用呢?

方法一:引用计数法,一个对象被引用的时候引用次数就+1,引用次数为0的认为就是垃圾对象,但这样会产生互相引用,会导致这俩永远都不会被认为是垃圾(非法抱团)

方法二:可达性分析法,简单说就是和GC Roots对象没有关系的就都是垃圾,那GC Roots是啥呢?比如上面提到的栈桢,那里面就有引用,栈顶的栈桢一定是当前执行的程序,那里面的引用肯定有用,这就可以是GC Roots,也就是说和他扯上关系的一个不能动!

GC Roots还有:本地方法栈中的引用、方法区中静态属性引用的对象、方法区中静态常量池中引用的对象。

 

 

有哪些垃圾清除方式

标记清除:识别到是垃圾标记下,然后直接清除即可,这种办法简单粗暴,但是会造成碎片问题,假如有20MB,我已经清除了10MB,但可能由于空间很分散,一块一块的,就可能会导致我一个需要连续1MB存储空间的对象都放不下,这就是碎片问题!

这个能避免吗?

 

复制算法:我把空间分两个区域,每次只用其中一个区域,需要清理的时候把活对象复制到另一个区域,再清空垃圾,这不就没有碎片了

吗?这样虽然没有碎片问题,但其实内存利用率也不高,归根揭底和标记清除都有着内存利用的短板

 

标记-整理:我不需要划分空间,我给碎片移动到一起不就行了,每次我标记好,完事把活着的移动到一端,再进行清理就OK了,不过这显然有些慢的

没有完美的方法?是的,好像是没有,毕竟这个空间换时间,时间换空间 ,这词语不是平白捏造的.....,但是按特性分配劳动力往往也能解决一些事情

 

下面来聊聊我自己的看法

先聊下Java对象,正常情况下我们所创建的很多对象,也就只用那一会的,所以说很多对象都是朝生夕死的,这些实例可以说是产的多死的快,所以这就意味这需要频繁的进行垃圾清除,但是也一定是有一些相对长期存在的对象。

那综合上述实例特点和三种算法比较:

1、对于朝生夕死的对象,使用第三种应该是不合适的,因为它需要频繁移动,效率低。那再看第一种,由于多,那好像也很容易产生碎片,折中好像只能取第二个!第二种用率低,但是我们可以只要一小部分内存,大不了我们先把大对象单独拿出来,很大的对象应该也很少吧。另外我们再想想,大部分(98%)朝生夕死,小部门一次清理中能留下来,总感觉可以用很小的空间就能给他存下来,那我们就划分一小部分,那就假设出来一小部部分。

现在我们可以想象有两块 大A,小b:

一开始把对象都存到大A,等到清理的时候,把活的移动到小b,然后清空大A内存,之后再把对象都往大A里放,之后再清除,等等,此时好想需要清除两部分,而且没有第三个空间可以用了,那就再造个第三空间吧,想一想,这个第三空间应该多大?显然只需要很小,因为我存储的也只是存活的!

现在我们可以想象有三块了, 大A,小b,小c

接着上面等等来,两块全部标记之后,把活的全移动到小c内,再把大A和小b 清空,这样下次清理又有一个空白内能用,好像挺不错的哈

2、那再看长期存在的,没啥说的,就用第三种了,虽然慢但是我不频繁!那上面说的大对象咋办呢?大对象,那碎片问题应该可以忽略不计的,因为比你小的对象一定是占大多数的!你被清理了腾出来的空间一定是很大的,我再时不时用第三种整理下,这样好像真的很不错!

这样综合来看,我们好像可以把内存分为四个区域(大A 小b 小c 存长期和大对象的)

 

然后再看下JVM的堆内存模型,,,哎,居然和他一样啊,没错就是一样,因为我就是根据那个自己假设的,,,,

 

 

清除过程:第一次清除之前,from和to 都是空的,老年代不一定是空的,因为就像上面说的,如果一个对象足够大会直接进入老年的,i第一次清除,会整理Eden区,把存活对象放到from

第二次清除,会整理Eden区和from区,然后把存活的放入to区,清空from,然后from和to再互换身份,也就是说第一次之后,from总是存放对象的,to总是空的!

之后的每次清楚就会循环第次清楚的步骤!

进入老年代的情况:

1、Eden园区存不下,进行清理,清理之后from区也放不下,那此时就会启动担保机制,使一些对象进入老年代

2、对象够老,也就是上面自已YY的长期对象,怎么判断够老?每次进行from-to转移时,把存活的都给他+1,默认活过15次清除进入老年代

 

两个GC概念

Minor GC:年轻代垃圾清除

 

Full GC:老年代垃圾清除(可手动:System.gc)

 

具体有哪些清除工具

个人认为理解几个概念就行

有针对上述各个算法实现的,有在清楚时会让业务线程全部暂停的,有和业务线程并发执行的

 

串行垃圾收集器

Serial和Serial Old,一般两者搭配使用。

新生代采用Serial,是利用复制算法;老年代使用Serial Old采用标记-整理算法。

-XX:+UseSerialGC开启串行垃圾回收器。

 

并行垃圾收集器

ParNew:Serial收集器的多线程版本,默认开启的收集线程数和CPU数量一样,运行数量可以通过修改ParallelGCThreads设定。用于新生代手机,复制算法。

用-XX:+UseParNewGC,和Serial Old收集器组合进行内存回收。

 

G1从整体看还是基于标记-清除算法的,但是局部上是基于复制算法的。

 

4、垃圾清除落地实现

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

借助Log360实现综合可见性的增强网络安全

当今的企业对技术的依赖程度前所未有,因此强大的威胁检测和响应策略变得至关重要。在现代世界中,网络犯罪分子不断寻找新的、富有创意的方式,以侵入组织的网络并窃取敏感数据。综合性的可见性是一个关键要素,有时被忽视&#xff0…

23-properties文件和xml文件以及dom4j的基本使用操作

特殊文件 我们利用这些特殊文件来存放我们 java 中的数据信息,当数据量比较大的时候,我们可以利用这个文件对数据进行快速的赋值 对于多个用户数据的存储的时候我们要用这个XML来进行存储 关于这些特殊文件,我们主要学什么 了解他们的特点&…

Linux系统编程基础:进程控制

文章目录 一.子进程的创建操作系统内核视角下的父子进程存在形式验证子进程对父进程数据的写时拷贝 二.进程等待进程非阻塞等待示例: 三.进程替换内核视角下的进程替换过程:综合利用进程控制系统接口实现简单的shell进程 进程控制主要分为三个方面,分别是:子进程的创建,进程等待…

windows修改键位F11变insert(改键盘映射)

这里是通过改变windows的注册表来实现的 1.按住winr打开运行,在运行中输入“regedit”,再点击“确定”按钮。如下图 2.找到注册表的目录 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 3.在Keyboard Layout右击新建 -> 二进…

18scala笔记

Scala2.12 视频地址 1 入门 1.1 发展历史 … 1.2 Scala 和 Java Scala Java 编写代码使用scalac编译成.class字节码文件scala .class文件 执行代码 1.3 特点 1.4 安装 视频地址 注意配置好环境变量 简单代码 1.5 编译文件 编译scala文件会产生两个.class文件 使用java…

OpenGLES:绘制一个颜色渐变、旋转的3D立方体

一.概述 之前关于OpenGLES实战开发的博文,不论是实现相机滤镜还是绘制图形,都是在2D纬度 这篇博文开始,将会使用OpenGLES进入3D世界 本篇博文会实现一个颜色渐变、旋转的3D立方体 动态3D图形的绘制,需要具备一些基础的线性代数…

mysql面试题8:MySQL的日志有哪些?MySQL的bin log、redo log、undo log区别和联系

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL的日志有哪些? MySQL的日志有以下几种,以及查看这些日志的命令和操作步骤如下: 错误日志(Error Log): 查看错误日志的命令:SHOW VARI…

2023.10.01-winxpsp3绿色安装jdk1.8

参考: 如何在XP系统配置java8(jdk8)环境 - 简书 jdk-8u381-windows-i586.exe jdk-8u202-windows-i586.exe 实验了一下,8u381不支持winxp xp3 下载地址: https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.htmlhttps://download.oracle.com/otn/ja…

基于Java的电影院购票系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

Strategy

Strategy 动机 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂; 而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对…

buuctf-[WUSTCTF2020]颜值成绩查询

打开环境,随便输个1看看 输个2 发现功能就是输入一个学号,然后返回对应的成绩,就是一个简单的查询操作。 当输入的学号不存在时,只会返回“student number not exists.”。 猜测是盲注题,因为看不见其他的回显信息&a…

计算机毕业设计 基于SSM的民宿推荐系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

【iptables 实战】05 iptables设置网络转发实验

一、网络架构 实验效果,通过机器B的转发功能,将机器A的报文转发到机器C 本实验准备三台机器分别配置如下网络 机器A ip:192.168.56.104 机器C ip:10.1.0.10 机器B 两张网卡,分别的ip是192.168.56.106和10.1.0.11 如图所示 如下图所示 二、…

软件安全需求分析

一、实验目的 熟悉软件安全需求分析方法,掌握软件安全分析技术。 二、实验软硬件要求 1、操作系统:windows 7/8/10等 三、实验预习 《软件安全技术》教材第6章 四、实验内容(实验步骤、测试数据等) 1. 目标:完成一…

10个与AI相关的技术领域

**10个与AI相关的技术领域** 除了与各个科学领域相关的具体挑战之外,AI在科学领域还存在一些共同的技术挑战。特别是,我们确定了以下四个共同的技术挑战:超出分布的泛化、可解释性、由自监督学习提供支持的基础模型和不确定性量化。尽管这些…

SpringBoot Validation入参校验国际化

在 Spring Boot 中,可以使用 Validation 和国际化来实现对入参的校验。 常用的校验 NotNull验证字段值不能为 nullNotEmpty验证字段值不能为 null 或空字符串NotBlank验证字符串字段值不能为空、null,并且必须至少包含一个非空白字符Size验证字符串、…

【PickerView案例12-info_plist-PCH文件介绍 Objective-C语言】

一、给大家介绍一下我们项目的一些文件: 1.这个呢,是项目的基础文件: 一些类啊: 一些图片啊: 还有加载图片, 最主要,就是这个东西:info.plist:文件 info.plist: 2.那,需要大家了解一点,关于它的历史啊: 我们现在用的时候,都是从xcode6.4开始的, 或者说,直…

【Shiro】SpringBoot集成Shiro权限认证《下》

本章节是在上一节的基础上继续完成,如有不明白,请看上一篇文章【Shiro】SpringBoot集成Shiro权限认证《上》。 SQL语句 这里我们需要先准备好SQL语句,如下所示: /* Navicat MySQL Data TransferSource Server : local Source Serv…

美丽的图论

**美丽的图论 ** Prf 😉 对于 n 个顶点上的树的数量 n^(n-2),这是凯莱公式,用于计算 n 个顶点上的树的数量,被放置在一个由 4 个标记顶点组成的圆圈中。 使用 Figma 制作 在图论中,树只是一个没有环的图。 树在离散…

Python机器学习-灵敏度分析

文章目录 灵敏度分析详细步骤单参数分析 灵敏度分析详细步骤 灵敏度分析是一种用于确定输入参数变化对模型输出结果的影响程度的方法。以下是进行灵敏度分析的一般步骤: 确定模型:选择需要进行灵敏度分析的模型,该模型必须具有可变参数和可…