深入浅出JVM

在这里插入图片描述

JVM内存模型

在这里插入图片描述
栈、本地方法栈、程序计数器都是线程独占,堆、方法区都是线程共享的。面试时主要回答两个点:

  1. 各部分的功能
  2. 哪些是线程共享的,哪些是线程独占的

是线程私有的,线程在执行每个方法时候都会创建一个栈帧,用来存储局部变量表和动态链接,方法出口等信息,调用方法时执行入栈,方法返回时执行出栈。

本地方法栈

与栈类似,也是用来保存线程执行方法时的一些信息,不同的是执行java方法时使用栈,执行native方法(一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C)时使用本地栈。

程序计数器

保存着当前线程执行的字节码位置,每个线程工作时都有一个独立的计数器。程序计数器只为执行java方法服务,执行native方法时程序计数器为空。

是JVM管理中最大的一块,堆被所有线程共享,目的是为了存放对象的实例,几乎所有对象的实例都会存放在这里。当堆内存没有可用的空间时,会抛出OOM异常。
根据堆对象存活的周期不同,JVM把堆内存进行分代管理,由垃圾回收器来进行垃圾的回收管理。

方法区

也是JVM中各个线程共享的区域,又叫C堆区,用于存储已被虚拟机加载的类信息、常量、静态变量、JVM优化后的代码等等。JDK1.7前的永久代和1.8后的MeteSpace都是方法区的一种实现。

JMM内存模型

在这里插入图片描述
是java的内存模型,和JVM内存模型是不一样的,JMM的目标定义程序中变量的访问规则。如上图所示,所有的共享变量都存储在主内存中共享,每个每个线程有自己的工作内存,工作内存中保存的是主内存变量的副本,线程中所有对变量的操作必须在自己的工作内存中执行,而不能直接读写主内存中的变量。
在多线程进行数据交互时,例如线程A、B,先由线程A读取这个变量,线程A修改完了变量是修改在自己的工作内存区中,线程B是不可见的,只有从A的工作内存区写回到主内存,线程B从主内存读取到后才能进行进一步的操作。由于指令重排序的存在,这个写和读的顺序有可能会被打乱,因此JMM需要提供原子性、可见性、有序性的保证

类的加载与卸载

在这里插入图片描述

类的加载

在这里插入图片描述
双亲委派的好处:

  1. 避免类的重复加载
  2. 避免java的核心api被篡改

分代回收

在这里插入图片描述
堆内存被分代管理,为什么?
主要是为了方便垃圾回收,这样做是基于两个事实:第一是大部分对象很快就不会使用,第二是还有一部分不会立即不使用但也不会持续很长时间。
虚拟机中划分为年轻代、老年代、永久代。看上图,

  • 年轻代主要是用来存放新创建的对象,分为Eden区和两个Surivor(幸存)区,大部分对象是在Eden区,当Eden区满时还存活的对象会在两个Survivor区交替保存,达到一定次数后,对象会晋升到老年代。
  • 老年代主要保存年轻代晋升来的对象信息。
  • 永久代主要来保存类信息

根据引用计数法、复制法、标记清楚法几种:

  • 引用计数法:通过对象被引用的次数来确定对象是否还在被使用,缺点是无法解决循环引用的问题。
  • 复制算法:需要from、to两块大小相同的内存空间,对象分配时只在from块进行,回收时把存活对象复制到to块中,并清空from块,然后交换两块的分工,把from块做为to块,把to块作为from块。缺点是内存使用率较低。
  • 标记清除算法:分为标记和清楚不再使用的对象两个阶段,缺点是会产生内存碎片。例如CMS、G1、ZGC

CMS算法

在这里插入图片描述
是JDK1.7以前最主流的算法。
第一个阶段是初始标记,标记的结果集只是从root直接可达的对象,会出现stop the world。
第二个阶段是并发标记,GC线程和应用线程并发执行,主要是标记可达的对象。
第三个阶段是重新标记,这个阶段是第二个stop the world阶段,停顿时间比并发标记要小很多,但比初始标记稍长,主要对对象进行重新扫描并标记。
第四个阶段,是并发清理阶段,主要对垃圾的清理。
最后一个阶段是并发重置阶段,为下一次GC准备相关数据结构

G1算法

在这里插入图片描述
在JDK1.9后成为了JVM的默认垃圾回收算法,G1的特点是保持高回收率的同时,减少停顿。G1算法取消了年轻代和老年代的物理划分,但它任然属于分代回收,G1算法将堆分为若干个区域reigen,如上图小方格所示,一部分区域用作年轻代,一部分用作老年代,还有另外一种专门用于存储巨型对象的分区,G1和CMS一样都遍历全部对象,然后标记对象引用情况,在清楚对象后,会对区域进行整合异动,整合碎片空间。
上图右边是G1的回收过程:

ZGC算法

在这里插入图片描述
可以支持tb级别的堆,它非常高效,能够做到10ms以下的回收停顿时间,这么短的停顿时间,ZGC是如何做到的呢?我们来了解下ZGC的黑科技:

  • 着色指针:一个指针最大是64位,ZGC限制了指针只能占42位,这样寻址只会使用到42位 ,那么剩余的22位就可以用来保存额外的信息,ZGC就是利用指针的额外信息位在指针上对对象进行着色标记。
  • 读屏障:来解决GC贤程和应用线程可能会并发修改对象状态的问题,而不是简单粗暴的使用STW来做全局的锁定,锁定只会在单个对象上产生,这样垃圾回收的大部分时候都不需要STW,因此ZGC的大部分时间都是并发处理
  • 基于Region:不像G1是固定大小,而是动态决定大小,Region可以动态创建和销毁。这样可以更好的对大对象进行分配和管理。
  • 压缩整理:CMS算法清理垃圾时是原地回收,会存在碎片问题。ZGC和G1一样也会在回收后对Region对象进行合并。

在这里插入图片描述
上图就是ZGC的回收过程

面试考察点

1深入理解JVM内存模型

2了解类加载机制

3了解内存可见性

4了解常用的GC算法实现和适用场景

5能够根据业务场景选择合适JVM参数和GC算法

加分项

1编译器优化

编译器优化方面有深入了解的话,会让面试官觉着你对技术深度角有追求。例如如何利用栈上分配减少内存压力,如何编写适合内联代码的问题等等

2问题排查经验和思路

面试官都喜欢动手能力强的同学,例如解决过线上经常fullGC的问题,排查过内存泄露的问题

3JVM调优经验与思路

针对特定场景的优化经验或思路,例如针对高平发低延迟的场景如何调整jvm参数尽量降低停顿时间,针对队列处理如何尽可能提高吞吐率等等

4了解最新的技术趋势(例如ZGC、Graalvm)

真题汇总

1.简单描述下JVM的内存模型

2.什么情况下会触发FullGC

年轻代晋升时,老年底内存不足时

3.Java类加载器有几种,关系是什么?

4双亲委派机制的加载流程是怎样的?有什么好处?

51.8为什么使用Metespace替换掉PermGen?Metespace保存在哪里?

6 编译期会对指令做哪些优化?(简单描述编译器的指令重排)

7简单描述下volatie可以解决什么问题?如何做到的?

强制主内存读写同步及防止指令重排序两点

8 简单描述下GC的分代回收

9 G1回收算法与CMS算法的区别在哪里?

10 对象引用有哪几种方式,有什么特定?

强弱软虚四种引用,以及在Jav中的处理方式

11使用过哪些JVM调试工具,主要分析哪些内容?

java自带的这些工具,例如堆分析工具Mat,线程分析工具jstack,获取堆信息的JMap等等

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值