1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

Update 搞定JVM垃圾回收就是这么简单.md

This commit is contained in:
SnailClimb 2019-05-04 09:13:12 +08:00
parent 15fc507aff
commit c8bb5cb0f7

View File

@ -1,8 +1,43 @@
上文回顾:[《可能是把Java内存区域讲的最清楚的一篇文章》](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484303&idx=1&sn=af0fd436cef755463f59ee4dd0720cbd&chksm=fd9855eecaefdcf8d94ac581cfda4e16c8a730bda60c3b50bc55c124b92f23b6217f7f8e58d5&token=506869459&lang=zh_CN#rd)
<!-- TOC -->
- [JVM 垃圾回收](#jvm-垃圾回收)
- [写在前面](#写在前面)
- [本节常见面试题](#本节常见面试题)
- [本文导火索](#本文导火索)
- [1 揭开 JVM 内存分配与回收的神秘面纱](#1--揭开-jvm-内存分配与回收的神秘面纱)
- [1.1 对象优先在 eden 区分配](#11-对象优先在-eden-区分配)
- [1.2 大对象直接进入老年代](#12-大对象直接进入老年代)
- [1.3 长期存活的对象将进入老年代](#13-长期存活的对象将进入老年代)
- [1.4 动态对象年龄判定](#14-动态对象年龄判定)
- [2 对象已经死亡?](#2-对象已经死亡)
- [2.1 引用计数法](#21-引用计数法)
- [2.2 可达性分析算法](#22-可达性分析算法)
- [2.3 再谈引用](#23-再谈引用)
- [2.4 不可达的对象并非“非死不可”](#24-不可达的对象并非非死不可)
- [2.5 如何判断一个常量是废弃常量](#25-如何判断一个常量是废弃常量)
- [2.6 如何判断一个类是无用的类](#26-如何判断一个类是无用的类)
- [3 垃圾收集算法](#3-垃圾收集算法)
- [3.1 标记-清除算法](#31-标记-清除算法)
- [3.2 复制算法](#32-复制算法)
- [3.3 标记-整理算法](#33-标记-整理算法)
- [3.4 分代收集算法](#34-分代收集算法)
- [4 垃圾收集器](#4-垃圾收集器)
- [4.1 Serial 收集器](#41-serial-收集器)
- [4.2 ParNew 收集器](#42-parnew-收集器)
- [4.3 Parallel Scavenge 收集器](#43-parallel-scavenge-收集器)
- [4.4.Serial Old 收集器](#44serial-old-收集器)
- [4.5 Parallel Old 收集器](#45-parallel-old-收集器)
- [4.6 CMS 收集器](#46-cms-收集器)
- [4.7 G1 收集器](#47-g1-收集器)
- [参考](#参考)
<!-- /TOC -->
# JVM 垃圾回收
## 写在前面
### 本节常见面试题:
### 本节常见面试题
问题答案在文中都有提到
@ -22,8 +57,6 @@
当需要排查各种 内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。
## 1 揭开 JVM 内存分配与回收的神秘面纱
Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时Java 自动内存管理最核心的功能是 **堆** 内存中对象的分配与回收。
@ -38,9 +71,7 @@ Java 堆是垃圾收集器管理的主要区域,因此也被称作**GC堆Ga
上图所示的 eden 区、s0 区、s1 区都属于新生代tentired 区属于老年代。大部分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 `-XX:MaxTenuringThreshold` 来设置。
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/89294547.jpg)
![堆内存常见分配策略 ](http://pqrlmrv7w.bkt.clouddn.com/img/2019-4/堆内存.jpg)
### 1.1 对象优先在 eden 区分配
@ -218,7 +249,7 @@ JDK1.2以后Java对引用的概念进行了扩充将引用分为强引用
## 3 垃圾收集算法
![垃圾收集算法](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/1142723.jpg)
![垃圾收集算法分类](http://pqrlmrv7w.bkt.clouddn.com/img/2019-4/垃圾收集算法.jpg)
### 3.1 标记-清除算法
@ -227,13 +258,13 @@ JDK1.2以后Java对引用的概念进行了扩充将引用分为强引用
1. **效率问题**
2. **空间问题(标记清除后会产生大量不连续的碎片)**
![标记-清除算法](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/63707281.jpg)
<img src="http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/63707281.jpg" alt="公众号" width="500px">
### 3.2 复制算法
为了解决效率问题,“复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
![复制算法](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/90984624.jpg)
<img src="http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/90984624.jpg" alt="公众号" width="500px">
### 3.3 标记-整理算法
根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
@ -252,7 +283,7 @@ JDK1.2以后Java对引用的概念进行了扩充将引用分为强引用
## 4 垃圾收集器
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/41460955.jpg)
![垃圾收集器分类](http://pqrlmrv7w.bkt.clouddn.com/img/2019-4/垃圾收集器.jpg)
**如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。**
@ -357,12 +388,11 @@ G1收集器的运作大致分为以下几个步骤
**G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region(这也就是它的名字 Garbage-First 的由来)**。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 GF 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。
## 参考
- 《深入理解 Java 虚拟机JVM 高级特性与最佳实践(第二版》
- https://my.oschina.net/hosee/blog/644618
- <https://docs.oracle.com/javase/specs/jvms/se8/html/index.html>