```PhantomReference<String> phantom = new PhantomReference<>(new String("hello"), new ReferenceQueue<>());```它完全**不会影响对象的生存时间**,唯一的作用是在对象被回收时发一个系统通知。

2.4 起死回生

对象在被判定为死亡后,并不会立刻被回收,而是要经过一个过程才会被回收。在这个回收过程中,死亡对象还有可能活过来,是不是很神奇?

来看图:

上图是对象被回收的过程。一个对象要被回收,至少要经过两次标记

如果对象在第二次标记之前重新连接上GC Roots,那么它将在第二次标记中被移出回收队列,从而复活。

还有一点需要注意的是,Finalizer线程是一个由虚拟机自动建立,且低优先级的线程。该线程触发对象的finalize()方法之后,并不会阻塞等待方法执行结束。这样做是为了防止回收队列被阻塞。

finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存之前被调用的方法。有些教材推荐用该方法来做“关闭外部资源”之类的工作,但是实际上该方法运行代价高昂,且不确定性很大,所以并不推荐使用。真要关闭外部资源,还不如用try-finally来处理。

3.方法区的回收


方法区不在堆内,会被垃圾回收吗?

在jdk1.7中,方法区在永久代,而永久代本身就是垃圾回收概念下的产物,full gc时就会对方法区回收。

到了jdk1.8,虽然永久代被取消,但是新增了MaxMetaspaceSize参数,对于将死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行。

所以,方法区会被回收。

4.垃圾回收算法


这一节我们来看下流行的垃圾回收算法,只说思想,不涉及实现细节。

我们需要了解的垃圾回收算法有以下几种:

  • 标记-清除算法

  • 复制算法

  • 标记-整理算法

  • 分代回收算法

咱们一个个来看下。

4.1 标记-清除算法

标记-清除算是最基本的回收算法了。它的思想就是先标记,再清除。标记过程如2.4节所述,有两次标记。

它的主要缺点有两个:

  • 效率不高

  • 会产生大量内存碎片

内存碎片是指内存的空间比较零碎,缺少大段的连续空间。这样假如突然来了一个大对象,会找不到足够大的连续空间来存放,于是不得不再触发一次gc。

4.2 复制算法

复制算法的思想是,把内存分成两块,假设分成A、B两个区域吧。

每次对象过来之后,都放到A区域里,当A区域满了之后,把存活的对象复制到B区域,然后清空A区域。

接下来的对象就全部放到B区域,等B区域满了,就把存活对象复制到A区域,然后清空B区域。

就这样来回倒腾,完成垃圾回收。

优点是不会有空间碎片缺点是每次只用得到一半内存

缺点是在对象存活率较高的场景下(比如老年代那样的环境),需要复制的东西太多,效率会下降

4.3 标记-整理算法

标记-整理算法中的“标记”阶段和“标记-清理”中的标记一样。不同的是,死亡对象并不会直接清理,而是把他们在内存中都移动到一起,然后一起清理。

4.4 分代收集算法

分代收集算法其实没什么新东西,只是把对象按存活率分块,然后选用合适的收集算法。

java中使用的就是分代收集算法。

存活率低的对象放在一起,称为年轻代,使用复制算法来收集。

存活率高的对象放在一起,称为老年代,使用标记-清除或者标记-整理算法。

5. HotSpot的枚举GC Roots


前面我们说到了对象的可达性分析需要从GC Roots开始计算引用链。

然而可作为GC Roots的对象非常多,一个个来计算将非常耗时。

而且在进行这项工作时,虚拟机必须停下来,就像时间停止那样(Sun称之为Stop The World,哈哈,是不是很酷),以此保证分析结果的准确性。

我们的程序,特别是网站应用,基本是上是一刻不停的在运行的。如果出现长时间的停止,基本上是不可接受的。为了解决这个问题,各个虚拟机都采取了一些措施,尽量减少停顿时间(是的,只能减少,停顿是不可能消除的)。

我们来看看现在最流行的Hotspot虚拟机是怎么处理的。(还记得啥是HotSpot不?翻翻前几篇文章)

5.1 OopMap

在HotSpot中,虚拟机把对象内的什么偏移量上是什么类型的数据的信息存在到一个叫做“OopMap”的数据结构中。这样在计算引用链时直接查OopMap即可,不用到整个内存中去挨个找了,由此提高了分析速度。

5.2 安全点

然而,程序中的引用关系时时刻刻都在变化,如果每次变化都要记录到OopMap中,也是一项很大的负担。所以,只有在程序执行到了特定的位置,才会去记录到OopMap中。

这个“特定的位置”,就叫安全点

这里面还有个问题,就是如何保证在GC发生时,让所有的线程正好到达安全点。

有两种方式:

  • 抢先式中断(已经没人用了)

    抢先式中断的思路是,先把所有线程中断,如果有线程没有跑到安全点上,就恢复该线程,让它跑到安全点。

  • 主动式中断

    主动式中断的做法是,设置一个中断标志,这个标志和安全点是重合的。让各个线程去轮询这个标志,发现需要中断时,线程就自己中断挂起。

5.3 安全区域

虽然安全点已经完美解决了如何保证在GC发生时,让所有的线程正好到达安全点的问题。

但是有一些情况下,线程失去了行为能力,比如线程处于sleep或者blocked状态。这个时候线程无法去响应JVM的中断请求,而JVM显然也不肯能一直等待某几个线程。该怎么办呢?

这种情况就需要“安全区域”来解决。

安全区域是指在一段代码片段中,引用关系不会发生变化,这个区域中任意地方开始GC都是安全的。

6.垃圾收集器


前面咱们说的都是垃圾收集的方法和思路,垃圾收集器则是具体的实现。

先来看下hotSpot中垃圾收集器的总图(到jdk1.8)

6.1 并行和并发

在开始讲解之前,我们先了解一下什么是并行和并发。

并行:垃圾收集器是多线程同时工作的,但是用户线程仍然处于等待状态。

并发:用户线程和垃圾收集器线程同时执行(也有可能是交替执行)。

下面咱们说说几个常用的使用方案

6.1 jdk1.8默认垃圾收集器

查看当前使用的垃圾收集器可以使用以下命令:


~ java -XX:+PrintCommandLineFlags -version

然后会看到以下内容:


-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGCjava version "1.8.0_151"Java(TM) SE Runtime Environment (build 1.8.0_151-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

可见jdk1.8默认工作在Server模式下,默认使用ParallelGC垃圾收集器

如果要看更详细的信息,还可以使用以下命令:


java -XX:+PrintFlagsFinal -version | grep GC

这个命令打印的内容有点多,我们主要找值为true的信息。默认情况会有以下两行:


bool UseParallelGC                            := true    bool UseParallelOldGC                          = true 

6.1.1 Parallel Scavenge收集器

从上面的总图能看到,这是一个工作在年轻代的收集器,使用复制算法,是一个并行的多线程收集器。

它的目标是达到一个可控制的吞吐量。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值。比如虚拟机总共运行了100分钟,其中垃圾收集花了1分钟,那吞吐量就是99%。

6.1.2 Parallel Old收集器

Parallel Old是一个工作在老年代的收集器,使用“标记-整理”算法。也是一个关注吞吐量的垃圾收集器。

6.2 web应用垃圾收集器方案

ParallelGC组合重视的是吞吐量,非常适合在后台运算而不需要太多交互的场景。

对于需要大量交互的应用,比如web应用,则需要更短的停顿时间。

所以大多数web应用使用的是ParNew+CMS收集器方案。

6.2.1 ParNew收集器

parNew也是一个工作在年轻代的收集器,也使用复制算法,也是一个并行的多线程收集器。

为什么我要使用这么多“也”……

好吧,parNew看起来和Parallel Scavenge一模一样,但其实他们还是有区别的。

parNew是一个重视停顿时间收集器。

不过它最大的特点是:可以和CMS收集器组队工作。

Parallel Scavenge就不行……

6.2.2 CMS收集器

CMS是一款十分优秀的老年代垃圾收集器,响应速度快、停顿时间短,是现在大多数互联网公司的选择,大家要好好掌握。

CMS使用“标记-清除”算法,分为4个步骤:

  • 初始标记(STW)

  • 并发标记

  • 重新标记(STW)

  • 并发清除

其中,初始标记很快,只是标记一下GC Roots能直接关联到的对象。

并发标记和重新标记要Stop The World,并发标记就是在标记死亡对象,重新标记是为了修正并发标记期间发生变动的那部分对象。

从耗时来看,并发标记>重新标记>初始标记。

并发清除和并发标记耗时最长,但收集器线程是和用户线程一起并发执行的,所以没有停顿。

CMS固然优秀,但也有一些缺点:

  • 耗CPU资源

    收集器线程和用户线程并发工作,所以收集时会抢占CPU资源

  • 无法处理浮动垃圾

    浮动垃圾是指在标记过程之后出现的垃圾。这部分垃圾在本次回收中无法处理,只能等下次。

  • 产生碎片空间

    使用“标记-清除”算法就会有这个问题。不过可以通过参数设置开启碎片整理,比如3次回收后就来一次带碎片整理的回收。

6.3 G1收集器

G1收集器是目前最新的垃圾收集器,到jdk1.7时达到可商用程度。

G1收集器可以同时hold住年轻代和老年代,不需要和别的收集器搭配使用。

G1收集器使用的也是分代算法,它的思路是,把内存空间分成一个个小格子,每个格子称为一个Region。如下图:

优先回收价值大的Region。

年轻代使用并发复制算法,有STW。

老年代回收步骤大致可以分为以下几个:

  • 初始标记(STW)

  • 并发标记

  • 最终标记(STW)

  • 筛选回收(STW)

目前JDK1.9已经默认使用G1收集器,但是在JDK1.8版本中G1收集器似乎还有不少问题,使用的还不多。

7.内存分配策略


最后

提供一下免费的Java架构学习资料给大家,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

需要的朋友可以戳这里免费领取

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
3NDcxMDQtMTcxNjk1NTEzOS5qcGc?x-oss-process=image/format,png)

优先回收价值大的Region。

年轻代使用并发复制算法,有STW。

老年代回收步骤大致可以分为以下几个:

  • 初始标记(STW)

  • 并发标记

  • 最终标记(STW)

  • 筛选回收(STW)

目前JDK1.9已经默认使用G1收集器,但是在JDK1.8版本中G1收集器似乎还有不少问题,使用的还不多。

7.内存分配策略


最后

提供一下免费的Java架构学习资料给大家,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

需要的朋友可以戳这里免费领取

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。

Java开发面试准备,JVM垃圾回收面试题详解相关推荐

  1. JVM垃圾回收面试题详解,java开发语言基础知识

    所以这种算法已经没人用了. 2.2 可达性分析法 2.2.1 什么是可达性 可达性分析法就是目前的主流算法,也是java正在使用的算法. 它的做法是,通过一系列被称为"GC Roots&qu ...

  2. JVM垃圾回收3——参数详解(转载)

    基本参数说明  -client,-server 这两个参数用于设置虚拟机使用何种运行模式,client模式启动比较快,但运行时性能和内存管理效率不如server模式,通常用于客户端应用程序.相反,se ...

  3. JVM垃圾回收机制GC详解

    作为 Java 语言最重要的特性之一的自动垃圾回收机制,也是基于 JVM 实现的.那么,自动垃圾回收机制到底是如何实现的呢? 1.GC是干啥的? 进行资源的回收 1.1.对于 C/C++ 而言 对于C ...

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

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

  5. java学习笔记-4 JVM垃圾回收(GC)

    引言 jvm垃圾回收相关的问题是老生常谈的问题了,相信大家都有所了解,这里再进行相关的探讨,以加深理解.若文中有不正之言,望不吝指正. 本文将围绕以下几个点展开 1.为什么要进行垃圾回收 我们知道jv ...

  6. Java教程分享:JVM垃圾回收机制之对象回收算法

    前言 在前面的文章中,介绍了JVM内存模型分为:堆区.虚拟机栈.方法区.本地方法区和程序计数器,其中堆区是JVM中最大的一块内存区域,在Java中的所有对象实例都保存在此区域,它能被所有线程共享. 在 ...

  7. Java Garbage Collection基础详解------Java 垃圾回收机制技术详解

    最近还是在找工作,在面试某移动互联网公司之前认为自己对Java的GC机制已经相当了解,其他面试官问的时候也不存在问题,直到那天该公司一个做搜索的面试官问了我GC的问题,具体就是:老年代使用的是哪中垃圾 ...

  8. java垃圾回收 分代_Java分代垃圾回收策略原理详解

    一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对 ...

  9. JVM垃圾回收面试题

    目录 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区 别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何判断一个类是无用的类 ...

最新文章

  1. android源代码 abi,Android内核源码Abi目录学习笔记
  2. 数据库基础笔记(MySQL)2 —— 基础查询
  3. 2021年春季学期-信号与系统-第十三次作业参考答案-第八小题
  4. 以ajax请求方式进行文件下载操作失败的原因及解决方案
  5. SAP Spartacus ConfigInitializerService里的isStable属性
  6. python import如何使用_Python如何import其它.py文件及其函数
  7. 基于 Blazor 打造一款实时字幕
  8. 80% 的学校还在给新生上 C 语言,它们 OUT 了吗?
  9. word文字中的数字怎么自动变化_【天华学术】不会为毕业论文“美颜”,怎么办?...
  10. 读Cookie安全后的读后感
  11. webpack 使用教程
  12. Java StringTokenizer类使用方式
  13. 利用DEEPLABV3-RESNET101获取人体蒙版
  14. B站最近很火的damedane,unravel图片唱歌
  15. 支付宝技术期末考:专业技术蓝军首次对外公开
  16. 2019“我爱北京——市民新春联欢会”将现300人大合唱
  17. CF 1368G Shifting Dominoes
  18. win10停止更新_你的win10即将终止!各大版本服务终止日期大全,准备好了吗?...
  19. Javascript版开心农场
  20. 算法设计与分析基础 第一章谜题

热门文章

  1. 修改ntp服务器rac,RAC时间同步的两种方法【NTP时间同步服务器】
  2. 南京大学周志华教授综述论文:弱监督学习
  3. 追剪案列 2轴可接步进或伺服,smartPLC和维纶触摸屏程序
  4. 彻底删除mysql5.1_MySQL5.1安装与卸载教程
  5. 1-2(中文版)掌握音标和读音
  6. otis电梯服务器tt使用说明_OTIS TT电梯操作器操作指南
  7. android系统 红米 耗电量,蓝牙究竟有多费电? 手机蓝牙耗电量实测
  8. 再谈“我是怎么招聘程序员的”
  9. 准备笔试-埃森哲在线笔试
  10. 天河二号计算机与量子计算机,“天河二号”算出量子霸权标准