GC基础知识 --(gc定位和gc回收)

最近忙于找工作和写论文,抽空给自己充点GC方面的知识。

GC基础

1. 什么是垃圾

品言生意,垃圾即是在程序运行过程中已经被使用完毕,且之后不需要再被使用的对象。

从java语言来讲,即是一个对象没有引用变量指向他,就代表该对象是一个内存垃圾。

对于这种不需要再使用的对象,应当在合适的时机予以删除,否则内存占用过多会导致溢出。

2. 如何定位垃圾

2.1. Reference Count(引用计数)

GC基础知识 --(gc定位和gc回收)

使用计数器记录对象的引用情况,当count = 0时代表没有对象引用,即此对象为垃圾。

但是计数方式不能解决循环引用的问题,比如两个对象互相引用,此时双方count都不会为0,但二者又确实时垃圾。

2.2 Root Searching(根节点的有向图搜索)

    首先说明那些是根节点:虚拟机栈, 本地方法栈中JNI引用的对象,方法区中类静态属性引用的对象,方法区的常量引用的对象。

GC基础知识 --(gc定位和gc回收)

从此图可以很容易的了解到: 从根节点进行遍历,能遍历到的点都是有引用变量指向的点,而遍历不到的就是垃圾。

3. GC算法(正真对垃圾进行处理的算法)

3.1 Mark-Sweep(标记清除)

找出垃圾,对垃圾部分的内存进行标记,然后删除。

特点:此种删除算法容易产生碎片,因为删除的位置不确定且不连续,所以删除后空出的空间不连续,导致一些大的数据无法存放在已经GC的内存位置。

3.2 Copying(拷贝)

将内存分为相同的两部分,正常使用时只使用其中的一半。在需要gc时,将正在使用空间的有效数据copy到另一半未使用的空间。

两个空间在gc时交替使用。

特点:没有碎片的产生,但浪费空间较多,使用率几乎只有一半。

3.3 Mark-Compact(标记压缩)

在回收垃圾时,将有用的对象拷贝到一起,形成一整片的连续存储的区域。

特点:没碎片,空间使用率高,但是效率低下,效率低下的原因是在移动的时候需要进行线程同步。

4. JVM的内存分带模型

4.1 新生代(存活对象少):Eden + 2个suvivor区,后面有图示

4.2 老年代(存活对象多)

4.3 永久代(JDK 1.7)/ 元数据区(JDK 1.8)Metaspace

      1. 永久代 元数据 - 装载Class对象

      2. 永久代可以指定大小限制,元数据设不设置都可以,无上限(但受限于物理内存)、

      3. 字符串常量 1.7存放在永久代, 1.8存放在堆

5. 堆内存逻辑分区 

GC基础知识 --(gc定位和gc回收)

上图的数字为各个区内存大小的比例;

工作过程:(YGC和FGC不了解的可以看下面的知识补充)

1. 当new出对象时,默认在eden区找可以分配的内存,如果数据过大,则会直接放入老年代

2. 新生代在执行YGC时,大多数的对象都会被回收。假如遇到不需要被gc的对象,则将其放入survivor区(survivor分为0,1两区)

    初次YGC,eden活着的对象装入survivor0;

    再次YGC,eden活着的对象 + 存活的survivor0 装入survivor1;

    再次YGC,eden活 + survivor1活 装入survivor0;

    年龄够老, 进入老年代;

    suvivor装不下,装不下的装入老年代;

    老年代装不下(顽固分子太多),使用FGC(尽量少使用);

知识补充YGC(MinorGC)和FGC(MajorGC):

1.YGC和FGC是什么

   YGC :对新生代堆进行gc。频率比较高,因为大部分对象的存活寿命较短,在新生代里被回收。性能耗费较小。

   FGC :全堆范围的gc。默认堆空间使用到达80%(可调整)的时候会触发fgc。以我们生产环境为例,一般比较少会触发fgc,有时10天或一周左右会有一次。

2.什么时候执行YGC和FGC

   a.edn空间不足,执行 young gc

   b.old空间不足,perm空间不足,调用方法System.gc() ,ygc时的悲观策略, dump live的内存信息时(jmap –dump:live),都会执行full gc

3.YGC和FGC使用什么回收策略

   YGC使用copy, FGC使用Mark-Compact (标记压缩)

 

6. 常见的垃圾回收器

GC基础知识 --(gc定位和gc回收)

              此图来源于:https://www.bilibili.com/video/BV1u5411e73q?from=search&seid=15568635766152370642

6.1 Serial (用于年轻代,单线程,串行回收)

官方解释:a stop-the-world, copying collector which uses a single GC thread,即停下所有一切,开一个单线程进行GC,直到GC完毕。

6.2 Parallel Scavenge(用于年轻代,多线程)

官方解释:a stop-the-world, copying collector which uses multiple GC threads,即停下一切,并行GC

6.3 ParNew(用于年轻代,多线程,可配合CMS使用)

官网解释:

1. a stop-the-world, copying collector which uses multiple GC thread;

2. It differs from "Parallel Scavenge" in that it has enhancements that make it usable with CMS;

3. For example, "ParNew" does the synchronization needed so that it can run during the concurrent phases of CMS;

6.4 SerialOld

相对于Serial,用于老年区

6.5 ParallelOld

用于老年期的并行

6.6 ConcurrentMarksSweep (老年代,并发的、垃圾回收和应用程序同时运行,降低STW时间(200ms))

6.7 G1(10ms 无新老之分)

6.8 ZGC(1ms 无新老之分)

6.9 shenandoah(无新老之分)

6.10 Eplison

用于老年代,不去stop-the-world。太复杂,我回头再去了解,补上知识点。

7. 如何了解生产环境下的垃圾回收器

JVM命令行参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

JVM参数分类:标准: -开头,所有的HotSpot都支持

                         非标准: -X开头, 特定版本HotSpot支持特定命令

                         不稳定: -XX开头,可能要取消