【Java面试题1】简单说说JVM堆的内存结构和GC回收流程

简介: 【Java面试题1】简单说说JVM堆的内存结构和GC回收流程

【Java面试题1】简单说说JVM堆的内存结构和GC回收流程


文章目录

前言

JVM堆内存结构简述

JVM堆内存结构图

堆初体验

结构详情

新生代

老年代

永久代/元空间

GC回收流程

GC回收流程图

GC回收详细流程

查看JDK自带可视化堆空间图

总结


前言

我们在Java面试中,只要是2年以上经验,一定会问你一下关于JVM方面的问题。开发两年时间不能对JVM没有了解,如果你还不了解,说明你的学习与探索能力不高,不能给到应有的加分项哦!小编也是最近刚刚开始学习,总结一下最近的学习成果。方便以后看,也希望小伙伴们看到可以帮助到您!


JVM堆内存结构简述

JVM堆内存结构图

堆初体验

所有的对象实例以及数组都要在堆上分配,堆是垃圾收集器管理的主要区域,也被称为“GC 堆”,也是我们优化最多考虑的地方。因为在一个项目中,会不断地创建对象,都是在堆里创建,如果一直不回收就会导致OOM,我们听的最多的情况哈!还有经常说的JVM调优,也是对堆进行参数优化配置,达到最接近理想状态。

结构详情

新生代

大部分刚创建的对象首先都是放在年轻代,新生代内存按照 8:1:1 的比例分为一个 Eden 和两个 Survivor(Survivor from,Survivor to)。

1. Eden 空间

Eden空间:主要是存放刚刚创建的新对象,如果可以Eden空间充足,新对象直接存放在Eden中,如果对象过大,放不下则会触发 Minor GC(效率很快)

2. Survivor 空间

每次执行Minor GC,会将Eden区中存活的对象放到Survivor的From区,而在From区中,仍存活的对象会根据他们的年龄值来决定去向,逃过一次Minor GC年龄加1,默认年数为15,就要到老年区。(From Survivor和To Survivor的逻辑关系会在GC时发生颠倒: From变To , To变From,目的是保证有连续的空间存放对方,避免碎片化的发生,后面GC流程在详细说)


老年代

在新生代中经历了 N 次(默认15次)垃圾回收后仍然存活的对象,就会被放到年老代中。年老代中存放的都是一些生命周期较长的对象。当老年代内存满时触发 Major GC 即 Full GC,Full GC 发生频率比较低,执行时间也是Minor GC的十倍以上。在老年代的对象一般为:存活时间比较长的,还有就是比较大的对象。


永久代/元空间

Java8 以前永久代,受JVM 管理,java8 以后元空间,直接使用物理内存。元空间位于堆外,所以它的最大内存大小取决于系统内存,而不是堆大小,我们可以指定 MaxMetaspaceSize 参数来限定它的最大内存。

GC回收流程

GC回收流程图

Java8 以前永久代,受JVM 管理

GC回收详细流程

当一个新对象创建时,首先会来到新生区的Eden区中,这里进行第一次判断:判断当前新对象是否可以再Eden区放得下,如果放下我们直接放到Eden区分配内存即可;如果放不下时,就要进行一次Minor GC。此次GC我们展开来详细说一下:回收时进行第二次判断:判断Survivor0是否放得下,如果放得下Eden 区存活对象复制到一个 Survivor0 区,然后清空 Eden 区,当这个 Survivor0 区也存放满了时,则将 Eden 区和 Survivor0 区存活对象复制到另一个 Survivor1 区,然后清空 Eden 和这个 Survivor0 区,此时 Survivor0 区是空的,然后将 Survivor0 区和 Survivor1 区交换,即保持 Survivor1 区为空, 如此往复(对照上面两个区域来回切换)。当对象在 Survivor 区躲过一次 GC 的话,其对象年龄便会加 1,此时进行第三次判断:判断年龄是否达到阈值,默认情况下,如果对象年龄达到 15 岁。超过就会移动到老年代中。不超则继续在Survivor。(对照上图虚线框)

执行完Minor GC后,进行第四次判断:判断Eden区是否放得下,如果放得下就进行内存分配,如果放不下默认作为大对象放到老年区。此时进行第五次判断新对象是否在老年区放得下,如果放得下就进行内存分配;如果放不下则进行一次Major GC 即 Full GC(执行时间为Minor GC的10倍多),最后进行第五次判断:判断老年区是否放得下,如果放得下进行内存分配;放不下则直接报异常OOM,此时需要改变堆的内存大小了。


-Xmx:最大堆大小

-Xms:初始堆大小


查看JDK自带可视化堆空间图

1. Win + R 输入jvisualvm

GC回收详细流程

当一个新对象创建时,首先会来到新生区的Eden区中,这里进行第一次判断:判断当前新对象是否可以再Eden区放得下,如果放下我们直接放到Eden区分配内存即可;如果放不下时,就要进行一次Minor GC。此次GC我们展开来详细说一下:回收时进行第二次判断:判断Survivor0是否放得下,如果放得下Eden 区存活对象复制到一个 Survivor0 区,然后清空 Eden 区,当这个 Survivor0 区也存放满了时,则将 Eden 区和 Survivor0 区存活对象复制到另一个 Survivor1 区,然后清空 Eden 和这个 Survivor0 区,此时 Survivor0 区是空的,然后将 Survivor0 区和 Survivor1 区交换,即保持 Survivor1 区为空, 如此往复(对照上面两个区域来回切换)。当对象在 Survivor 区躲过一次 GC 的话,其对象年龄便会加 1,此时进行第三次判断:判断年龄是否达到阈值,默认情况下,如果对象年龄达到 15 岁。超过就会移动到老年代中。不超则继续在Survivor。(对照上图虚线框)

执行完Minor GC后,进行第四次判断:判断Eden区是否放得下,如果放得下就进行内存分配,如果放不下默认作为大对象放到老年区。此时进行第五次判断新对象是否在老年区放得下,如果放得下就进行内存分配;如果放不下则进行一次Major GC 即 Full GC(执行时间为Minor GC的10倍多),最后进行第五次判断:判断老年区是否放得下,如果放得下进行内存分配;放不下则直接报异常OOM,此时需要改变堆的内存大小了。


-Xmx:最大堆大小

-Xms:初始堆大小


查看JDK自带可视化堆空间图

1. Win + R 输入jvisualvm

2. 安装GC插件

JVM监控工具jvisualvm的使用及GC插件安装

3. 查看内存图

总结

这样一个大的面试题就描述完成了,主要是理解GC回收的流程懂了,堆的结构也就知道怎么回事了。

相关文章
|
5天前
|
运维 Java
Java版HIS系统 云HIS系统 云HIS源码 结构简洁、代码规范易阅读
云HIS系统分为两个大的系统,一个是基层卫生健康云综合管理系统,另一个是基层卫生健康云业务系统。基层卫生健康云综合管理系统由运营商、开发商和监管机构使用,用来进行运营管理、运维管理和综合监管。基层卫生健康云业务系统由基层医院使用,用来支撑医院各类业务运转。
26 5
|
1月前
|
Java
JAVA选择结构
JAVA选择结构
18 1
|
Java 数据安全/隐私保护
java实现加密电话号码,有具体的加密流程注释
java实现加密电话号码,有具体的加密流程注释
21 0
|
1天前
|
Java
Java基础知识整理,驼峰规则、流程控制、自增自减
在这一篇文章中我们总结了包括注释、关键字、运算符的Java基础知识点,今天继续来聊一聊命名规则(驼峰)、流程控制、自增自减。
32 3
|
13天前
|
算法 安全 Java
内存分配与回收策略
内存分配与回收策略
17 0
内存分配与回收策略
|
29天前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
73 0
|
1月前
|
Java
Java选择结构
Java选择结构
8 0
|
1月前
|
NoSQL 应用服务中间件 Linux
Redis的内存回收机制
Redis的内存回收机制
25 2
|
1月前
|
存储 Java
JAVA顺序结构
JAVA顺序结构
11 1
|
1月前
|
SQL Java 关系型数据库
flink cdc 内存问题之不会回收如何解决
Flink CDC(Change Data Capture)是一个基于Apache Flink的实时数据变更捕获库,用于实现数据库的实时同步和变更流的处理;在本汇总中,我们组织了关于Flink CDC产品在实践中用户经常提出的问题及其解答,目的是辅助用户更好地理解和应用这一技术,优化实时数据处理流程。