一、概念

1、JVM组成及作用

(1)组成:类加载器、运行时数据区(Java内存模型)、执行引擎、本地库接口

(2)作用:

类加载器(ClassLoader)把class文件转换成字节码;

运行时数据区(Runtime Data Area)把字节码加载到内存中;

特定的命令解析器执行引擎(Execution Engine),将内存中的字节码翻译成底层系统指令,再交由 CPU去执行

调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

2、内存模型JMM/运行时数据区

(1)组成

线程共享:堆、方法区(非堆,内存元空间,包括常量池)/永久代

线程私有:栈(虚拟机栈、本地方法栈)、程序计数器

(2)线程共享

a. 堆(GC堆):存放对象实例,是垃圾回收器的区域,可以细分为新生代和老年代;

更好地进行内存分配与回收,可以划分为多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB),存储的依旧是对象实例。

堆在逻辑上连续,物理上不连续,大小可固定可扩展。

堆中无法完成实例分配且无法扩展时,会抛出OOM(OutOfMemoryError)异常/内存溢出。

堆中一个空对象大小占8字节byte

b. 方法区:存储被JVM加载的常量、静态变量、类信息、即时编译代码等数据。

JVM中将其描述为堆的一个逻辑部分,也被称为非堆(Non-Heap)。

又可以分为运行时常量池和直接内存。

(3)线程独享

a. 程序计数器:当前线程所执行字节码的行号指示器

可以完成程序的分支、循环、跳转、异常处理、线程恢复等基础功能

为了便于多线程切换时能恢复到正确的执行位置,不会出现OOM

b. 栈:存放基本类型和堆中对象的引用

可以分为虚拟机栈和本地方法栈

虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,本地方法栈为虚拟机使用到的Native方法服务

可能会抛出StackOverflowError异常/栈溢出

一个对象只对应了一个4字节的引用(堆栈分离的好处)

3、为什么要进行堆栈分离

栈代表了处理逻辑,而堆代表了数据,分开使得处理逻辑更为清晰

堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象),栈中只需要记录堆的地址。

提供了一种有效的数据交互方式(如:共享内存),也可以节省内存

栈固定,而堆可以根据需要动态增长

4、对象的访问定位方式

使用句柄:堆中会划分出句柄池,池中存储对象的句柄地址,句柄中包含数据的具体地址

直接指针:存储类型和数据,修改时需要变两次指针

二、垃圾回收

1、判断可以回收的方法

引用计数法

可达性分析算法

2、从哪回收

由栈指向堆,从堆中回收

3、标为垃圾的对象会回收吗

不一定,至少经历两次标记

第一次标记:可达性分析后没有引用链,就会被标记

第二次标记:筛选没有重新与引用链建立联系的对象,进行第二次标记,执行finalize()方法,并进行回收;如果在finalize()方法中重新与引用链建立关联,则逃离本次回收,继续存活。

4、引用概念

引用分为强引用、软引用、弱引用、虚引用,四种引用强度依次减弱。

强引用:永不被回收

软引用:有用但非必须,内存溢出前进行回收,并将其加入引用队列

弱引用:只要被GC线程扫描到,就会被回收

虚引用:随时被回收,用于对象被回收时收到系统通知

5、垃圾回收算法

标记-清除(Mark-Sweep):会造成内存碎片

复制算法(Copying):有用的复制到另一边

标记-整理(Mark-compact):存活对象移动到最左端,解决内存碎片问题

分代收集:大部分JVM采取,划分为新生代、老年代,以及非堆的永久代(方法区)

6、为什么使用分代收集

(1)对象的生命周期不同,针对不同对象,采用不同收集方式,可以提高回收效率

(2)如String对象等临时变量,有些甚至一次回收;Session对象与业务挂钩,生命周期长

7、新生代Young回收

(0)Minor GC,频率高,无需等到eden区满后才触发,主要采用Copying算法

(1)新生成的对象均放在年轻代,目标是收集生命周期短的对象

(2)按8:1:1的比例分为eden区和两个survivor区(survivor0、survivor1)

复制清空

先将对象生成到eden区,回收时将存活对象复制到survivor0区,然后清空eden区;

当survivor0区存满时,将eden区和survivor0区存活对象复制到survivor1区,并清空eden区和survivor0区,并将survivor0区和survivor1区交换,保持survivor1区为空;

(3)当 survivor1 区不足以存放 Eden 区 和 survivor0区的存活对象时,将存活对象放至老年代;

(4)老年代满了,就会触发一次Full GC(major GC),同时回收新生代和老年代

8、老年代回收

(1)年轻代经历N次回收后仍然存活的对象(生命周期较长),就会进入老年代

(2)老年代内存是新生代的一倍,老年代对象存活率比较高

6、浮动垃圾

GC线程和工作线程并行运行,在垃圾回收过程中产生的垃圾,就产生了浮动垃圾,这些垃圾在下次垃圾回收时才能被回收

7、内存碎片

不同对象存活时间不同,不进行内存整理,就会出现内存碎片

复制和标记整理算法,均可以解决碎片问题

8、常见的垃圾回收器

(1)Serial(Old)串行收集器-单线程

使用复制算法,是client默认的方式

通过 -XX:+UseSerialGC 来强制指定

(2)ParNew收集器-多线程

ParNew:Serial的多线程版本

(3)Parallel Scavenge-高吞吐量的并行收集器

使用停止-复制算法,是server级别的默认GC方式

使用-XX:+UseParallelGC强制指定,用-XX:ParallelGCThreads=4指定线程数

(4)Parallel Old收集器-并行收集器

Parallel 收集器的老年代版本

(5)CMS(Concurrent Mark Sweep)收集器-并发收集器(同时开始工作)

使用标记-清除算法

以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器

加上“-XX:+UseConcMarkSweepGC”指定

注意:产生大量碎片,剩余内存无法运行,出现Concurrent Mode Failure

临时CMS采用Serial Old回收器进行垃圾清除,此时的性能将会被降低

(6)G1(Garbage-First)-分区模型

将内存分为多个Region

后台维护优先列表,根据收集时间,选择回收价值最大的Region

(7)〇暂停ZGC(Zero pause GC)

采用颜色指针,根据颜色指针决定是否做相应操作

从根开始找

标记位标记指针的状态,初始标记为M0

有M0就是有用的,没有 M0,是remapped就是垃圾

线程访问M0时,对应对象的标记就会换成M0

8、CMS垃圾回收器

(1)含义

Concurrent Mark-Sweep,并发标记-清除,以牺牲吞吐量为代价来获得最短回收停顿时间

(2)过程

初始标记:快速记录与root直接相连的对象,暂停其他线程;

并发标记:GC和用户线程同时开始,由于不断更新引用域,闭包内不能包含所有的可达对象,会记录引用更新位置;

重新标记:修正引用更新的位置,

并发清除:对未标记区域进行清扫

9、G1垃圾回收器

(1)分区:把整个堆划分为一个一个等大小的区域(region)。内存的回收和划分都以region为单位

(2)支持分代的垃圾回收

(3)区域优先:收集那些活跃对象小的 region,以便快速回收空间

10、垃圾回收策略/时机

(1)新生代的Minor / Scavenge GC

Eden区满后触发新生代的 Minor GC

Eden区不会分配很大,所以Eden区的GC会频繁进行

(2)老年代的Major GC-速度慢

何时会触发?

对于大对象,首先在Eden尝试创建,创建不了,就会触发Minor GC

随后继续尝试在Eden区存放,仍然放不下

尝试进入老年代,老年代也放不下

触发 Major GC 清理老年代的空间

(3)整个堆的Full GC

减少Full GC次数,对JVM的调优即对Full GC的调节

11、何时会导致Full GC

调用System.gc(),会建议虚拟机执行Full GC

大对象进入,导致老年代空间不足

永久代空间不足

空间分配担保失败:使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。

【面试题总结】JVM01-组成及垃圾回收的更多相关文章

  1. 面试题之C# 内存管理与垃圾回收

    面试题之C# 内存管理与垃圾回收 你说说C# 的内存管理是怎么样的 这句话我记了一个多礼拜了, 自从上次东北师大面试之后, 具体请看<随便扯扯东北师大的面试>. 国庆闲着没事, 就大概了解 ...

  2. 李洪强iOS经典面试题37-解释垃圾回收的原理

    李洪强iOS经典面试题37-解释垃圾回收的原理   问题 我们知道,Android 手机通常使用 Java 来开发,而 Java 是使用垃圾回收这种内存管理方式. 那么,ARC 和垃圾回收对比,有什么 ...

  3. 李洪强iOS经典面试题31-解释垃圾回收的原理

    李洪强iOS经典面试题31-解释垃圾回收的原理 问题 我们知道,Android 手机通常使用 Java 来开发,而 Java 是使用垃圾回收这种内存管理方式. 那么,ARC 和垃圾回收对比,有什么优点 ...

  4. JVM垃圾回收面试题

    Java垃圾回收有个经典面试题,什么时候,对什么对象,做了什么操作? 垃圾回收里涉及内容很多,要准确回答这个问题首先要先限定边界.分清楚虚拟机规范定义和不同虚拟机实现的差异.以工作中用到的hotspo ...

  5. 不止面试-JVM垃圾回收面试题详解

    第一部分:面试题 本次分享我们将尝试回答以下问题: GC 是什么? 为什么要有 GC? 简单说一下java的垃圾回收机制. JVM的常见垃圾回收算法有哪些? 为什么要使用分代回收机制? 如何判断一个对 ...

  6. 【搞定Jvm面试】 JVM 垃圾回收揭秘附常见面试题解析

    JVM 垃圾回收 写在前面 本节常见面试题 问题答案在文中都有提到 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好 ...

  7. JVM(十二),垃圾回收面试题

    十二.垃圾回收面试题 1.Object的finalize()方法 2.Java中的强软弱虚四种引用 (1)强引用 (2)软引用(间接引用) (3)弱引用 (4)虚引用 (5)四种引用区别

  8. .NET面试题系列[5] - 垃圾回收:概念与策略

    面试出现频率:经常出现,但通常不会问的十分深入.通常来说,看完我这篇文章就足够应付面试了.面试时主要考察垃圾回收的基本概念,标记-压缩算法,以及对于微软的垃圾回收模板的理解.知道什么时候需要继承IDi ...

  9. 面试题-Java基础-垃圾回收

    1.Java中垃圾回收有什么目的?什么时候进行垃圾回收? 垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源. 2.System.gc()和Runtime.gc()会做什么事情? 这两个方 ...

  10. 图解 CMS 垃圾回收机制原理,-阿里面试题

    最近在整理JVM相关的PPT,把CMS算法又过了一遍,每次阅读源码都能多了解一点,继续坚持. 什么是CMS CMS全称 ConcurrentMarkSweep,是一款并发的.使用标记-清除算法的垃圾回 ...

随机推荐

  1. 如何修改 Kubernetes 节点 IP 地址

    转载自:https://www.qikqiak.com/post/how-to-change-k8s-node-ip/ 昨天网络环境出了点问题,本地的虚拟机搭建的 Kubernetes 环境没有固定 ...

  2. centos7.2 安装MongoDB

    1.配置阿里云yum仓库 #vim /etc/yum.repos.d/mongodb-org-4.0.repo [mngodb-org] name=MongoDB Repository baseurl ...

  3. 第五章:Admin管理后台 - 2:自定义Admin actions

    通常情况下,admin的工作模式是"选中目标,然后修改目标",但在同时修改大量目标的时候,这种模式就变得重复.繁琐. 为此,admin提供了自定义功能函数actions的手段,可以 ...

  4. [题解] BZOJ 3456 洛谷 P4841 [集训队作业2013]城市规划 多项式,分治FFT

    题目 令\(f_i\)表示n个点的答案.考虑容斥,用所有连边方案减去有多个连通块的方案.枚举1号点所在的连通块大小: \(f_i=2^{i(i-1)/2}-\sum_{j>0}^{i-1}f_j ...

  5. Redis核心设计原理(深入底层C源码)

    Redis 基本特性 1. 非关系型的键值对数据库,可以根据键以O(1) 的时间复杂度取出或插入关联值 2. Redis 的数据是存在内存中的 3. 键值对中键的类型可以是字符串,整型,浮点型等,且键 ...

  6. GC plan_phase二叉树挂接的一个算法

    楔子 在看GC垃圾回收plan_phase的时候,发现了一段特殊的代码,仔细研究下得知,获取当前数字bit位里面为1的个数. 通过这个bit位为1的个数(count),来确定挂接当前二叉树子节点的一个 ...

  7. Python编程之定时任务(crontab)详解

    引言 python-crontab是python模块,提供了对cron任务的访问,并使得我们可以通过python对crontab文件进行修改. 安装 pip install python-cronta ...

  8. SpringBoot(五) - Java8 新特性

    1.Lambda表达式 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).使用它可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风 ...

  9. PHP + ELK实现日志记录

    一个简单的PHP 文件 效果 full.conf文件 流程: 开启logstash服务之后. 在业务代码里面操作函数写入日志.log logstash通过实践戳获取到用户的变更,取出最后一行数据,发送 ...

  10. 第一种方式:使用form表单将前端数据提交到servelt(将前端数据提交到servlet)

    第二种使用Ajax的形式将前台的数据传输到后台:https://blog.csdn.net/weixin_43304253/article/details/120335657 1.form表单 引入了 ...