面试害怕考到JVM? 看这一篇就够了~

news2024/11/24 10:55:07

目录

前言

一、JVM内存划分

二、类加载

2.1、类加载是在干什么?

2.2、类加载的过程

2.3、何时触发类加载?

2.4、双亲委派模型(重点考察)

2.4.1、什么是双亲委派模型?

2.4.2、涉及到的类加载器

2.4.3、详细过程图解

三、GC(垃圾回收机制)

3.1、STW问题(Stop The World)

3.2、GC回收哪部分内存?

 3.3、垃圾对象的判定算法

3.3.1、引用计数法(非JVM采取的办法)

3.3.2、可达性分析(JVM采取的办法)

3.4、垃圾回收算法

3.4.1、标记-清除算法

3.4.2、复制算法

3.4.3、标记整理算法

3.4.4、分代算法


前言

        面试中要考到有关JVM的话题,主要也就是三个方面:1.JVM内存划分,2.JVM类加载,3.JVM的垃圾回收;弄清楚这三个方面的内容,带你体会面试就如聊天?本篇会用通俗简洁的话,高效的带你理解JVM这三个模块!


一、JVM内存划分

        java程序,是一个名字为java的进程,这个进程就是所说的“JVM”;

        JVM 会从操作系统中申请一块大的内存空间,在此基础上分成几个小的区域;

区域划分如下图:

注意:上图中每一个虚线框都对应一个线程;程序计数器是每个线程都有一个;

这些区域分别存放什么?(面试如果问到,如下回答即可)

1.堆:存放new出来的对象;(成员变量)

2.方法区:存放的是类对象;(静态变量)

3.栈(虚拟机栈, 本地方法栈):存放方法之间的调用关系;(局部变量)

4. 程序计数器:存放的是下一个要执行的指令;

注意:变量存放在哪一个区域,和变量类型无关!和变量的形态(局部,成员,静态)有关!

测试:以下变量存放在什么位置?(笔试题中会出现)

 解释:

        变量a是成员变量,所以存放在堆里

        变量b是成员变量,所以存放在堆里

        变量c是静态变量,在类对象里,所以存放在方法区中;

        testHead这个引用是静态的,在方法区中,他new出的对象是在堆里的;

        test这个引用是局部变量,所以就在栈上,他new出的对象在堆中;


二、类加载

2.1、类加载是在干什么?

        java程序在运行之前,会先编译,也就是由 .java 编译成 .class文件(二进制字节码文件),运行的时候,java进程(JVM)就会读取到对应的 .class 文件,并解析内容,在内存中构造出类对象进行初始化;

简而言之就是: 类 从 文件 加载到内存中;

2.2、类加载的过程

下图为类的生命周期:

 解释:

        前 5 步是固定的顺序并且也是类加载的过程,其中中间的 3 步我们都属于连接,所以对于类加载来 说总共分为以下五个步骤:

  1. 加载;
  2. 连接 =>(1.验证、2.准备、3.解析);
  3. 初始化;

对类加载步骤的解释:

1. 加载:找到 .class 文件,读取文件内容,按照 .class 规范的格式来解析;

2. 验证:检查当前的 .class 里的内容格式是否符合要求;

3. 准备:给类里的静态变量分配内存空间;

        例如,static int a = 6; 这段代码在准备阶段就会给a分配4个字节的内存空间,同时这些空间的初始值都是0;

4. 解析:初始化字符串常量,把符号引用(占位符)替换成直接引用(内存地址)

        例如,String str = "hello!"; 类加载之前,"hello!"这个字符串常量并没有分配内存空间,因此 str 里就无法保存字符串常量的真实地址,只能使用一个占位符标记一下(标记了这里是"hello!"这个字符串常量的内存地址),等到真正给"hello!"分配了内存后(类加载完后),就可以用真正的地址代替之前的占位符;

5.初始化:针对类进行初始化,初始化顺序如下

        父类(静态变量、静态代码块)–>子类(静态变量、静态代码块)–>父类(变量、代码块)–> 父类构造器–>子类(变量、初始化块)–>子类构造器。

注意:静态代码和静态变量同级,变量和代码块同级。谁在前先执行谁。类只会初始化一次。

2.3、何时触发类加载?

        这里并不是程序一启动就加载了,而是类似于[ 懒汉模式 ] ,使用到这个类的时候,才会触发加载;

怎么算才是使用到这个类?

1. 创建了这个类的实例;

2. 使用了类的静态方法/静态属性;

3.实用类的子类(加载子类会触发加载父类);

2.4、双亲委派模型(重点考察)

2.4.1、什么是双亲委派模型?

        一个类加载器收到类加载请求,首先自己不会加载这个类,而是把这个请求委派给父类加载器完成,每一层都是如此,因此所有加载请求最终都会送到最顶层的加载器中,只有父加载器反馈无法加载这个请求,子类才会尝试去加载;

2.4.2、涉及到的类加载器

1. Bootstrap ClassLoader :负责加载标准库中的类;

2. Extension ClassLoader:负责加载JVM扩展的库的类(标准库中没有,但JVM自己实现出了);

3. Application ClassLoader :负责加载我们自己的项目中的自定义类;

2.4.3、详细过程图解

         有意思的是,上述过程并未涉及到 “双亲”,只是 “单亲”,这里的 “双亲” 实际上是机翻出来的,更直白其实可以叫 “单亲委派模型”...

 


三、GC(垃圾回收机制)

        在学习C语言的过程中,需要通过 malloc 申请内存,最后通过 free 进行释放,这里就容易存在一个问题——忘记free,造成内存泄漏;而GC(垃圾回收)就是一个主流处理方案;

GC是干什么的呢?

        就是一个自动释放内存的机制;我们只需要负责申请内存,释放内存的工作交给JVM完成,JVM会自动判定当前内存是否不再使用,若不再使用,就自动释放;(类似开车 => 手动挡 升级 自动档)

3.1、STW问题(Stop The World)

        C++为何不引入GC?因为GC存在一个最大的问题就是会引入额外的 “空间+时间” 开销;

        空间上:消耗额外的CPU / 内存资源; 

        时间上:最大的问题——STW问题(Stop The World);

什么是STW问题?

        当程序运行到需要GC释放内存的时候,就有需要消耗一定的时间,反应到用户这里,就有可能存在明显的卡顿;

        那那那那...为什么我们还要用他?因为在实际的开发中,开发效率是大于运行效率的~

3.2、GC回收哪部分内存?

        方法区?类对象加载一次之后便不会卸载;栈?释放时机确定,不用回收;程序计数器?固定内存空间,不必回收;GC主要就是针对堆来回收的;

如下图:

 3.3、垃圾对象的判定算法

如何判断一个某个对象是否是垃圾?

        如果一个对象没有任何引用能够指向他,这个对象就是视为垃圾了;

3.3.1、引用计数法(非JVM采取的办法)

注意:此方法不是JVM采取的方法,Python、PHP使用这个方法;

        具体的,给每个对象加上一个计数器,这个计数器就表示 “当前的对象有几个引用”;

如下图:

解释:

        每多一个引用指向该对象,计数器就+1;

        每少一个引用指向该对象,计数器就-1;

        当计数器的数值为0时,就说明这个对象已经没有人能够再使用了,此时就可以进行释放;

存在缺点:

        1. 空间利用率低,尤其是小对象(例如:计数器本身大小为int,对象里也只有一个int大小的成员,相当于空间增加了一倍);

        2. 可能出现循环引用的情况,如下:

 解释:

        当前这两个对象引用计数器为1,因为即使t1, t2两个引用被置为空,但实际上时两个对象在相互引用,此时外界代码是无法访问的,但由于引用计数器不是0,所以无法进行释放;

3.3.2、可达性分析(JVM采取的办法)

        约定一些特定的变量,成为 “GC roots”, 每隔一段时间,从GCroots出发,进行遍历,查询哪些变量是能够被访问到的,能被访问到的变量就称为 “可达”,否则就是 “不可达”;

GC roots对象可以是以下几种:

        -- 栈上的变量;

        -- 常量池引用的对象;

        -- 方法区中静态属性引用对象;

        -- 方法区中常量引用的对象;

具体的如下图:

解释:

        上图中,通过 GC roots就可以找到object1、object2、object3、object4;而object5、6、7则不可以被访问到,所以5、6、7就是垃圾了;

3.4、垃圾回收算法

3.4.1、标记-清除算法

        简单来说,就是标记出垃圾后,直接把对象对应的内存空间进行释放;

如下图:

解释:

        上图中,黑色部分就是被标记要清除的部分,经过回收后,就剩下了存活对象;

缺点:

        1.效率:标记和清除这两个过程的效率都不高;

        2.空间(内存碎片):如上图,标记就清除后会产生大量不连续的内存碎片,碎片太多可能会导致之后程序运行中需要分配较大对象时,可能无法找到连续且足够大的空间而无法申请空间;

3.4.2、复制算法

         这是针对内存碎片问题,引入的办法;

         具体的,将内存分成两块大小相等的空间,但只使用其中的一块,当需要进行垃圾回收时,就把正在使用的那块空间上还存活的对象复制到另一块上,再将使用过的那块内存全部清空;这样做的好处就是不用在考虑内存碎片问题;

如下图: 

缺点:

        1. 空间利用率相比标记清除法更低了;

        2. 若一轮GC下来,大部分需要保留,只有极少数要回收,这时候复制的开销就很大了;

3.4.3、标记整理算法

        标记过程与 “标记-清除算法”一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端连续性的覆盖,然后直接清除掉边界以外的空间;(类似于顺序表的删除元素)

如下图:

 评价:

        相对于复制算法而言,空间利用率提升了,同时也解决了内存碎片化问题,但是搬运操作比较耗时;

3.4.4、分代算法

        分代算法总和了上面所说的三种算法,通过区域划分,实现不用区域用不同的垃圾回收策略,从而实现更好的垃圾回收;也就是我们常说的“因地制宜”~

如下图:

 解释:

        1. 刚创建出来的对象,进入伊甸区;

        2. 若新对象熬过一轮GC,没挂,就通过复制算法,复制到生存区;

        3. 生存区的对象也要经历GC,每熬过一次GC,就会通过复制算法拷贝到另一个生存区(只要这个对象不死亡,就会在两个生存区来回拷贝);

        4. 如果一个对象在生存区中,反复坚持了很多轮还没去世,就会被放到老年代(老年代GC的频率会降低);

        5. 若对象来到了老年代,也会进行定期的GC,只是频率更低了;老年代采取标记整理的方式来处理垃圾;

        特殊处理:若新创建的对象非常大,则直接进入老年代;因为一个大的对象进行复制算法,开销太大;另一个角度考虑,既然是一个很大的对象,费这么大开销创建出来,肯定不是立即就销毁的;


 

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

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

相关文章

【树莓派】raspberry pi控制超声波测距

目录一、超声波1、模块介绍2、工作原理二、gettimeofday函数三、树莓派控制超声波测距一、超声波 1、模块介绍 简介:   超声波传感器模块上面通常有两个超声波元器件,一个用于发射,一个用于接收。 硬件: 电路板上有4个引脚: …

测试面试被问“期望薪资多少”,不要傻傻直接报价,高情商都这样说

对于软件测试从业者而言,面试很重要,因为那是拿到薪资报酬丰厚程度的关键,你的理论及实操经验确实都很棒,那就尽量别让自己的面试表现拖自己的后腿,否则大概率会让你的薪水大打折扣。 你在面试中是否也遇到很多次以下…

38寻找二叉树的最近公共祖先39序列化和反序列化

38.寻找二叉树的最近公共祖先 这题和上一题的区别在于这不是二叉搜索树,无法根据值的大小来判断节点的位置,于是需要遍历 法1 递归写法 递归在左右子树寻找o1和o2 import java.util.*;/** public class TreeNode {* int val 0;* TreeNode left …

12月编程语言排行榜公布啦~

2022年迎来了最后一个月,我们可以看到,在这一年中编程语言起起伏伏,有的语言始终炙手可热,而有的语言却逐渐“没落”...... 日前,全球知名TIOBE编程语言社区发布了12月编程语言排行榜,有哪些新变化&#x…

Test Squence测试过程中如何按照特定条件暂停或者停止仿真

在Simulink模型做Test Squence测试时,工程师有时候希望测试用例能按照自己期望的条件来停止或暂停仿真,这个期望的特定条件,可以是时间达到,也可以是任何能达到的特定状态。 具体实现方法如下: 1、在Test Harness测试…

公司 CTO:高性能开发,你不会 Netty,怎么好意思拿 20K?

主管:这个版块用 Netty 框架就可以了呀,不会吗? (此时,公司 CTO 路过) 某程序员:这个我真不会... 主管:好了好了,那这一块我交给别人去做,这个也不难啊&am…

代码随想录刷题记录day36 整数拆分+不同的二叉搜索树

代码随想录刷题记录day36 整数拆分不同的二叉搜索树 参考:代码随想录 343. 整数拆分 思想 一个数可以被拆分成2个数或者3个及以上的数。 dp[i]表示拆分i以后,得到的最大的乘积 拆分成两个数 j和i-j,拆分成三个数及以上 j 和dp[i-j],dp[i…

面试10分钟就完事了,问的实在是太...

干了两年外包,本来想出来正儿八经找个互联网公司上班,没想到算法死在另一家厂子。 自从加入这家外包公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到11月一纸通知,所有人不许加班,薪资…

【矩阵乘法】C++实现外部矩阵乘法

问题描述 ​ 使用文件和内存模拟系统缓存,并利用矩阵乘法验证实际和理论情况。 算法思想 设计一个Matrix类,其中Matrix是存在磁盘中的一个二进制文件,类通过保存的矩阵属性来读取磁盘。前八个字节为两个int32,保存矩阵的行列数…

Linux||报错:vboxuser is not in the sudoers file. This incident will be reported.

一、问题描述 打算在Ubuntu虚拟机上部署SonarQube时,为避免各种不必要的奇怪问题,预先使用sudo命令修改系统参数。 命令如下:sudo sysctl -w vm.max_map_count262144 报错如下:vboxuser is not in the sudoers file. This inciden…

制造业企业库存管理的现状与解决措施

在竞争激烈的现代经济时代,制造行业面临着巨大的挑战和压力,必须与时俱进,适应市场的各种变化才能生存并保持活力。随着经营模式的变化与产品数量的增加,对产品库存管理也提出更大的挑战。库存管理是指与库存相关的计划和控制活动…

数据库设计 Relational Language

除了最为常用的SQL语句之外,还存在着几种不常用的数据库语言,这里简单介绍,了解即可。 Relational Algebra(RA) 一种程序性语言,可以与SQL对应着转换,语法即转换规则如下: σ:与WHERE对应&am…

一篇文章让你搞懂各种压缩,gzip压缩,nginx的gzip压缩,Minification压缩

前言 同学们可能听过这些压缩,但是可能不是了解,这篇文章让你弄清他们 webpack的gzip压缩和nginx的gzip压缩有什么区别?怎样开启gzip压缩?Minfication压缩又是什么鬼?怎样使项目优化的更好?本篇文章讲的是…

DBCO点击试剂1629057-08-4,DBCO-C3-Maleimide,DBCO-C3-Mal

一、基础产品数据(Basic Product Data): CAS号:1629057-08-4 中文名:二苯基环辛炔-C3-马来酰亚胺、二苯并环辛炔-C3-马来酰亚胺 英文名:DBCO-C3-Maleimide,DBCO-C3-Mal 结构式(Struc…

MAC 通过IDEA启动tomcat,显示80端口被占用解决办法

mac系统下使用IntelliJ IDEA中的Tomcat报错问题:Address localhost:80 is already in use 一、状况描述 本人在跑一个tomcat的项目时,由于项目限制了用域名访问,为了方便本地开发调试,需在tomcat在IDEA中将端口设置为80&#xff…

three.js问题记录---MeshLambertMaterial材质颜色失效

初学three.js,跟着教程走都比较顺利,自己尝试写个demo的时候发现创建一个物体,在给材质颜色的时候出现了一个问题。 在three.js官网文档(https://www.techbrood.com/threejs/docs/)中,我们可以看到材料&am…

论文解读-Early Detection of Cybersecurity Threats Using Collaborative Cognition

1 概述与介绍 作者描述了一种新颖的协作框架,该框架通过利用语义丰富的知识表示和与不同机器学习技术集成的推理功能来协助安全分析人员。文中介绍的认知网络安全系统从各种文本源中提取信息,并使用一种扩展的UCO安全本体的将其存储在知识图谱中。该系统…

[附源码]Python计算机毕业设计SSM家庭安防系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

一个ubuntu系统搭建redis集群

下载redis(如果要搭建redis集群不建议使用命令下载,因为后面启动集群时redis5.0一下的会有问题,依赖ruby) 更新apt sudo apt update使用apt下载 sudo apt install redis-server打开redis配置文件 sudo vim /etc/redis/redis.conf设置远程连接&#x…

2023年tiktok自动化运营软件新排名看这里!

【导读】2022年即将结束啦,你的tiktok运营效果怎么样呢?这里我们小编告诉您,用tiktok自动化运营软件可以取得事半功倍的效果哦!这里就带大家看看2023年tiktok自动化运营软件排名哦! 2023年tiktok自动化运营软件新排名看…