JVM垃圾回收

垃圾回收简介,垃圾回收器介绍,如何调优,调优的基本思路。

主要内容参考:黑马 JVM

目录

垃圾回收

判断(谁被回收)

四种引用

分代垃圾回收工作机制

简述分代垃圾回收器是怎么工作的?

你知道一个对象怎么从新生代变成老年代吗

如果子线程堆区溢出,会影响主线程的正常运行吗?

垃圾回收策略(怎么回收)

新生代垃圾回收器和老年代垃圾回收器都有哪些?有什么区别?

垃圾回收器

Serial + Serial Old串行

Parallel + Parallel Old吞吐量优先

CMS响应时间优先

CMS回收过程可以分为哪些步骤?

CMS的问题

CMS的特点

G1 GC(综合)

分区回收过程:

G1垃圾回收器的改进是什么?相比于CMS突出的地方是什么?

追问3:现在jdk默认使用的是哪种垃圾回收器?

调优

新生代调优

老年代调优


垃圾回收

判断(谁被回收)

引用计数法:早期的python虚拟机使用

可达性分析算法:找到根对象,凡是直接或者间接引用到根对象上,就不被回收

从一个被称为 GC Roots 的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。

这个算法的实质在于将一系列GC Roots作为初始的存活对象合集(live set),然后从该合集出发,探索所有能够被该合集引用到的对象,并将其加入到该和集中,这个过程称之为标记(mark)。 最终,未被探索到的对象便是死亡的,是可以回收的。

摘自:JVM-可达性分析算法 - 知乎

哪些是根对象?

GC Roots可以理解为由堆外指向堆内的引用, 一般而言,GC Roots包括(但不限于)以下几种:

  1. Java 方法栈桢中的局部变量;
  2. 已加载类的静态变量;
  3. JNI handles;
  4. 已启动且未停止的 Java 线程

比如:系统类的、锁对象、线程相关的 都是根对象,比如 object,string等

jmt和 jmap 指令联合可以查看堆区的根对象

四种引用

Java四种引用类型 - Helldorado - 博客园(附带代码Java四种引用类型 - Helldorado - 博客园(

强 软 弱 虚

强引用:GC root对象可以直接到达的对象就是强引用的对象,一般在程序中创建的都是强引用的,只有当没有引用的时候才会回收。

软引用:由一个GC root 关联一个软引用对象,软引用又会关联一个对象,这就是软引用对象,当发生垃圾回收且内存不够时,就会回收。

软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

弱引用:由一个GC root 关联一个弱引用对象,弱引用又会关联一个对象,这就是弱引用对象,当发生垃圾回收就会回收。

软引用和弱引用会进入引用队列,线程会在后台 扫描 引用队列,定期释放这两个引用自身。

虚引用:必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队, 由 Reference Handler 线程调用虚引用相关方法释放直接内存

NIO的时候会用到,因为是直接内存,所以gc 管不到,只能通过虚引用,再加一个线程去手动释放

终接器引用

无需手动编码,但其内部配合引用队列使用,在第一次垃圾回收时,终结器引用入队(被引用对象

暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize

方法,第二次 GC 时才能回收被引用对象

强 > 软 > 弱 > 虚引用

 

分代垃圾回收工作机制

简述分代垃圾回收器是怎么工作的?

分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。

新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:

  • 把 Eden + From Survivor 存活的对象放入 To Survivor 区;
  • 清空 Eden 和 From Survivor 分区
  • From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。

每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。

老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。

你知道一个对象怎么从新生代变成老年代吗

一个对象初始分配在伊甸园,新生代空间不足 触发minor gc 如果该对象存活 就会复制到 to区

交换from to,年龄加一,几次新生代空间不足 进行gc后 年龄达到阈值就会进入老年代。

通过调试程序可以看到 垃圾回收的具体过程。

特例: 堆区存储大对象时 如果新生代不够 老年代够 那么会直接晋升

如果都不够,直接堆区溢出

如果子线程堆区溢出,会影响主线程的正常运行吗?

其实发生OOM的线程一般情况下会死亡,也就是会被终结掉,该线程持有的对象占用的heap都会被gc了,释放内存。因为发生OOM之前要进行gc,就算其他线程能够正常工作,也会因为频繁gc产生较大的影响。

一般不会影响其他线程工作。

高德面试官问我:JVM内存溢出后服务还能运行吗,我一顿操作行云流水_wj1314250的博客-CSDN博客_oom程序还能运行吗

一个进程一个堆 一个线程一个栈

垃圾回收策略(怎么回收)

标记清除

优点 速度快

缺点 空间不连续 有内存碎片

复制算法

双倍内存空间 效率较低

标记整理

没有内存碎片 效率较低

在新生代中可以使用复制算法,但是在老年代就不能选择复制算法了,因为老年代的对象存活率会较高,这样会有较多的复制操作,导致效率变低。

标记-清除算法可以应用在老年代中,但是它效率不高,在内存回收后容易产生大量内存碎片。因此就出现了一种标记-整理算法(Mark-Compact)算法,与标记-清除算法不同的是,在标记可回收的对象后将所有存活的对象压缩到内存的一端,使他们紧凑的排列在一起,然后对端边界以外的内存进行回收。回收后,已用和未用的内存都各自一边。

优点:解决了标记-清除算法存在的内存碎片问题。

缺点:仍需要进行局部对象移动,一定程度上降低了效率。

分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,

新生代基本采用复制算法,老年代采用标记整理算法。

新生代垃圾回收器和老年代垃圾回收器都有哪些?有什么区别?

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1

垃圾回收器

Serial + Serial Old串行

堆内存较小,适合个人电脑。

不然要耗费很长时间

新生代单线程收集器,标记和清理都是单线程,优点是简单高效;

Parallel + Parallel Old吞吐量优先

新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;

堆内存较大 多核cpu 适合 服务器,gc总时间短 适合科学计算等任务

分布式计算

CMS响应时间优先

Concurrent Mark Sweep。

看名字就知道,CMS是一款并发、使用标记-清除算法的gc。

CMS是针对老年代进行回收的GC。

在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景。

好文

CMS垃圾收集器执行过程_lz710117239的博客-CSDN博客_cms垃圾收集器过程icon-default.png?t=M1L8https://blog.csdn.net/lz710117239/article/details/78565926

多线程

堆内存较大 多核CPU

gc 单次时间短

适合互联网的低延迟需求

CMS回收过程可以分为哪些步骤?

(1)初试标记:初试标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,但需要暂停所有其他的工作线程。

(2)并发标记:GC 和用户线程一起工作,执行GC Roots跟踪标记过程,不需要暂停工作线程。

(3)重新标记:在并发标记过程中用户线程继续运作,导致在垃圾回收过程中部分对象的状态发生了变化,未来确保这部分对象的状态的正确性,需要对其重新标记并暂停工作线程。

(4)并发清除:清理删除掉标记阶段判断的已经死亡的对象,这个过程用户线程和垃圾回收线程同时发生。

需要重新标记 是因为在并发的过程中待回收的对象可能会变多,或者原来被判定为垃圾的现在被强引用了。

CMS的问题

(1)CMS收集器对处理器资源非常敏感。

(2)CMS是基于标记-清除算,产生大量的空间碎片。

(3)如果并发失败,响应时间就会变得很长。

具体的:

cms 并发失败 (因为碎片太多,需要整理) 就会退化为 串行parallel 的, 响应时间就会变的很长

CMS的特点

特点一

老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。

特点二

CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器(标记-整理)进行垃圾清除,此时的性能将会被降低。

G1 GC(综合)

Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。

g1 比cms更强,没有内存碎片 兼顾吞吐量和响应时间

分区回收过程:

G1垃圾回收器的改进是什么?相比于CMS突出的地方是什么?

回答:G1垃圾回收器抛弃了分代的概念,将堆内存划分为大小固定的几个独立区域,并维护一个优先级列表,在垃圾回收过程中根据系统允许的最长垃圾回收时间,优先回收垃圾最多的区域。(G1算法是可控STW的一种算法,GC收集器和我们GC调优的目标就是尽可能的减少STW的时间和次数。)

G1突出的地方:

基于标记整理算法,不产生垃圾碎片。

可以精确的控制停顿时间,在不牺牲吞吐量的前提下实现短停顿垃圾回收。

追问3:现在jdk默认使用的是哪种垃圾回收器?

回答:

jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

jdk1.9 默认垃圾收集器G1

调优

jvm调优应该放在最后,代码 调优优先

新生代调优

老年代调优

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

trigger333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值