学完了这篇JVM,面试官真拿我没办法了!
在我们面试中经常会遇到面试官问一些有关JVM的问题,下面我大概从运行时数据域、类加载机制、类加载器、垃圾收集器、垃圾收集算法、JVM堆内存模型、JVM内存结构、JVM调优等几个方面来讲一下JVM。
一、运行时数据区域
在执行Java程序的时候,JAVA虚拟机会将自己所管理的内存划分为若干个不同的数据区域,每个区域分工不同,这些区域统称为“运行时数据区域”。下面来根据一张图来看一下这几个区域。
1、程序计数器
1>较小的内存空间。
2>当前线程字节码的行号指示器。
3>改变计数器的值来选取下一条需要执行的字节码指令。
4>一个处理器只会执行一条线程中的指令,为了线程切换后能恢复到正确的执行位置,每个线程一个计数器。
2、Java虚拟机栈
1>线程私有。
2>生命周期与线程相同。
3>每个方法执行都会创建栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
3、本地方法栈
1>线程私有。
2>使用到的本地(Native)方法服务。
4、Java堆
1>内存中最大的一块。
2>线程共享。
3>堆满了抛出OutOfMemoryError异常。
5、方法区
1>线程共享。
2>用于存储已被虚拟机加载的类型信息、常量、静态变量、及时编译器编译后的代码缓存等数据。
6、运行时常量池(次区域在方法区内部)
1>运行时常量池是方法区的一部分。
2>存放各种字面量与符号引用。
二、垃圾收集算法
1、标记-清除算法
首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象。如图。
2、标记-复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。如图。
3、标记-整理算法
标记-整理算法就是标记-清除算法后再将存活对象整理到一起,从而腾出来更大的连续空间。如图。
三、垃圾收集器
1、Serial收集器
Serial收集器是最基础、历史最悠久的收集器,这个收集器是一个单线程工作的收集器。
2、ParNew收集器
ParNew收集器实质上是Serial收集器的多线程并行版本,可以同时使用多条线程进行垃圾收集。
3、Parallel Scavenge 收集器
Parallel Scavenge收集器是一款新生代收集器,它是基于标记-复制算法实现的收集器。Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值,即。
4、Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器。
5、Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,支持多线程并行收集,基于标记-整理算法实现。
6、CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,它的运作过程分为四个步骤,包括:
1> 初始标记
2> 并发标记
3> 重新标记
4> 并发清除
初始标记:初始标记需要stw,初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。
并发标记:并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。
重新标记:重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短。
并发清除:这个阶段清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
6、Garbage First 收集器(简称G1收集器)
G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。如图。
G1收集器的运作过程大致可以划分为以下四个步骤:
初始标记:仅仅只是标记一下GC Roots能直接关联到的对象,
并发标记:从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。
最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。
筛选回收:负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。这里的操作设计存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。
四、类加载机制
当我们运行一个类的时候,我们会通过java.exe来调用jvm.dll文件,创建一个类加载器,然后再加载我们的类,我们的类在加载的过程中会经历加载、验证、准备、解析、初始化。
加载:此阶段将类的二进制字节流加载到内存中。
验证:此阶段将验证文件的格式、元数据验证、字节码验证、符号应用验证,保证这些代码运行后不会危害虚拟机自身的安全。
准备:准备阶段是为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始默认值。
解析:解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程,符号引用是用符号来描述所引用的目标,而直接引用是用地址来描述所应用的目标。
初始化:由于之前准备阶段是给静态变量赋值默认值,而初始化阶段是给静态变量赋值他的真实的值。
五、类加载器
1、启动类加载器:这个类加载器负责加载存放在<JAVA_HOME>\lib目录中的系统的jar。
2、扩展类加载器:这个类加载器负责加载存放在<JAVA_HOME>\lib\ext目录中的扩展类jar。
3、应用程序类加载器:这个类加载器负责加载我们自己写的类。
六、双亲委派模型
前面我们说到每个类会有一个对应的类加载器去加载这个类,而不同的类加载器所加载的类的类型不同,当我们要加载一个类的时候首先会去应用程序类加载器加载过的集合里(注:这里是加载过的集合里)查看有没有加载这个类,如果没有就去扩展类加载器加载过的集合里查看有没有加载过这个类,如果没有就再向上去找引导类加载器加载过的集合里看有没有加载过这个类,如果也没有就会从引导类加载器要加载的核心类中寻找有没有要加载的类,如果没有就向下寻找扩展类加载器中要加载的扩展类中有没有,如果也没有就去应用程序加载器中寻找。
好处:
1、不会重复去加载一个类,假如应用程序类加载器加载过Student类,那么下载再加载这个类的时候只需要判断应用程序类加载过的集合里有没有加载过这个类,如果加载过就不用再次加载了。
2、防止恶意修改核心类库,比如我们自己写一个String类,我们去运行这个类,系统会在引导类加载器中加载Java的核心类库中的String类,而不会加载我们自定义个的String类,这就防止我们私自篡改核心类库。
七、JVM堆内存模型
在JVM中我们的堆内存模型大概为图所示,我们新生成的对象会放到eden区,当我们eden区域放满了,我们会进行一个轻GC,会把eden区域和S0区域的存活对象放到S1区域,然后将eden区域和S0区域清空,然后新生成的对象接着放到eden区域,当eden区域再次满了,会将eden区域和S1区域的存活对象放到S0区域,然后将eden区域和S1区域清空,如此循环往复,没进行一次循环会将没有被清除的对象年龄+1,如果存活的对象年龄到达15(这个数值可以调整),就会将此对象放到老年代,或者是survivor区域满了也会将一些对象放到老年代,如果当老年代满了就会进行一次重GC。
八、JVM调优
所谓JVM调优主要就是减少堆内存中重GC的次数,这样我们就根据对象什么情况会进入老年代来进行分析,首先是存活15代(这个数值可以调整),这种情况一般就是一些常量等,这些一般不会有再大的优化空间,或者一些代码的问题造成循环调用,这种情况通过修改调整代码即可。其次是当survivor区域满了的话就会向老年代放入一些对象,这个时候我们就需要根据业务情况来调整堆内存的大小以及年轻代和老年代的比例,一般我们例如一些电商系统,一些订单对象进入内存中就是朝生夕是,订单从创建到持久化数据库中就不在内存中使用了,所以一些正常的业务产生的对象会在轻GC的时候被收回,但是有一些大对象可能放不下年轻代中所以就会放入老年代,这种情况我们就要调大堆内存中年轻代的大小,使得一些大对象可以放入到年轻代中,并随着轻GC被垃圾收集器收回。
学完了这篇JVM,面试官真拿我没办法了!的更多相关文章
- 面经手册 · 第12篇《面试官,ThreadLocal 你要这么问,我就挂了!》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 说到底,你真的会造火箭吗? 常说面试造火箭,入职拧螺丝.但你真的有造火箭的本事吗,大 ...
- 【笔记0-开篇】面试官系统精讲Java源码及大厂真题
背景 开始阅读 Java 源码的契机,还是在第一年换工作的时候,被大厂的技术面虐的体无完肤,后来总结大厂的面试套路,发现很喜欢问 Java 底层实现,即 Java 源码,于是我花了半年时间,啃下了 J ...
- Spring第二天,你必须知道容器注册组件的几种方式!学废它吊打面试官!
前一篇<不要再说不会Spring了!Spring第一天,学会进大厂!>文章可点击下方链接进行回看. 不要再说不会Spring了!Spring第一天,学会进大厂! 今天将继续讲解Spri ...
- 面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗
一.前言 不知道大家还记不记得前几篇的文章:<面试官:能解释一下javascript中的this吗> 那今天这篇文章虽然是介绍javascript中bind.apply和call函数 ...
- Spring第三天,详解Bean的生命周期,学会后让面试官无话可说!
点击下方链接回顾往期 不要再说不会Spring了!Spring第一天,学会进大厂! Spring第二天,你必须知道容器注册组件的几种方式!学废它吊打面试官! 今天讲解Spring中Bean的生命周期. ...
- 面试官:我们来聊一聊Redis吧,你了解多少就答多少
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,建议收藏关注 一.前言 作为一名Java程 ...
- 面试官:Redis如何实现持久化的、主从哨兵又是什么?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Redi ...
- 面试官:Redis集群有哪些方式,Leader选举又是什么原理呢?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Redi ...
- 面试官:Zookeeper是什么,它有什么特性与使用场景?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Zook ...
随机推荐
- JAVAEE_Servlet_11_GetAndPost
Get请求和Post请求 * Get请求 和 Post请求各方面分析 - 什么情况下浏览器发送的是Get请求? 1. 通过浏览器的地址栏输入地址,所访问的URL都是get请求,如果以post定义,那么 ...
- 浅谈synchronized和volatitle实现线程安全的策略
什么是线程不安全 我对线程安全的理解就是多个线程同时操作一个共享变量时会产生意料之外的情况,这种情况就是线程不安全.注意:只有写操作才可能出现线程不安全,对共享变量只进行读操作线程是绝对安全的. 具体 ...
- adb 简介与常用命令
1. abd 简介 2. adb 常用命令 1. abd 简介 adb 的全称为 Android Debug Bridge,就是起到调试桥的作用. 借助 adb 工具,我们可以管理设备或手机模拟器的状 ...
- gitlab支持https最简单方法
gitlab支持https方法 使用gitlab内部nginx直接支持https 通过外部nginx代理(本次使用的方法) 访问流程外部nginx--->gitlab的gitlab_workho ...
- CAP 5.0 版本发布通告
前言 今天,我们很高兴宣布 CAP 发布 5.0 版本正式版.同时我们也很高兴的告诉你 CAP 已经有越来越多的用户并且变得越来越流行. 在 5.0 版本中,我们主要致力于更好的支持 .NET 5 以 ...
- goloader - golang动态加载的实现
github地址:https://github.com/dearplain/goloader 这里有以前的一些思路:http://www.cnblogs.com/dearplain/p/8145985 ...
- @unittest.skip(reason):强制跳转。reason是跳转原因
在执行测试用例时,有时候有些用例是不需要执行的,那我们怎么办呢?难道删除这些用例?那下次执行时如果又需要执行这些用例时,又把它补回来?这样操作就太麻烦了. unittest提供了一些跳过指定用例的方法 ...
- 1.6.1- HTML中ul元素无序列表的使用
无序列表的各个列表项之间没有顺序级别之分,是并列的,语法如下: <ul> <li>列表项1</li> <li>列表项2</li> <l ...
- SQL 查询的执行顺序
SELECT语句的完整语法如下 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOIN & ...
- 【ElasticSearch】文档路由的原理
ElasticSearch集群环境下新增文档如何确认该文档被分配到哪个分片中? 路由算法: ⾸先这肯定不会是随机的,否则将来要获取⽂档的时候我们就不知道从何处寻找了.实际上,这个过程是根据下⾯这个公式 ...