垃圾回收机制之GC-简书

       线上服务器因为内存溢出导致服务器假死,部分请求通过nginx转发到这台机时访问报错,在排查生产问题时顺藤摸瓜的就找到了GC回收的问题,下面就来结合项目问题讲解一下GC

1、先通过 jstat -gcutil pid interval(ms)在linux中获取GC执行情况

jstat -gcutil  7698 1000

这里有11个参数,参数的意思分别为:

S0: 新生代中Survivor space 0区已使用空间的百分比

S1: 新生代中Survivor space 1区已使用空间的百分比

E: 新生代已使用空间的百分比

O: 老年代已使用空间的百分比

P: 永久带已使用空间的百分比

YGC: 从应用程序启动到当前,发生Yang GC 的次数

YGCT: 从应用程序启动到当前,Yang GC所用的时间【单位秒】

FGC: 从应用程序启动到当前,发生Full GC的次数

FGCT: 从应用程序启动到当前,Full GC所用的时间

GCT: 从应用程序启动到当前,用于垃圾回收的总时间【单位秒】

2、下面讲讲垃圾回收机制GC的工作原理

JVM组成:

1.类加载器(Class Loader):加载类文件到JVM内存。Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是由Exectution

Engine 负责的。

2.运行时数据区(Runtime Data Area)

3.执行引擎(Execution

Engine):也叫解释器,负责解释命令,交由操作系统执行。

4.本地库接口(Native

Interface):本地接口的作用是融合不同的语言为java所用


运行时数据区:
 (1)堆。堆是java对象的存储区域,任何用new字段分配的java对象实例和数组,都被分配在堆上,java堆可用-Xms和-Xmx进行内存控制,jdk1.7以后,运行时常量池从方法区移到了堆上。

(2)方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

(3)虚拟机栈:虚拟机栈中执行每个方法的时候,都会创建一个栈桢用于存储局部变量表,操作数栈,动态链接,方法出口等信息。

(4)本地方法栈:与虚拟机发挥的作用相似,相比于虚拟机栈为Java方法服务,本地方法栈为虚拟机使用的Native方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。

(5)程序计数器。指示Java虚拟机下一条需要执行的字节码指令。


判断垃圾算法:

●引用计数算法

    在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单

的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关 联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。

●可达性分析算法

   为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots” 对象作为起点搜索。如果在“GC

roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记

过程。两次标记后仍然是可回收对象,则将面临回收。

回收垃圾算法:

●标记清除算法(Mark-Sweep)

●复制算法(copying)

●标记整理算法(Mark-Compact)

●分代收集算法


标记清除算法(Mark-Sweep)

最基础的垃圾回收算法,分为两个阶段,标注和清除

                                                            缺点:从图中我们就可以发现,该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。


复制算法(copying)

为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小

的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用 的内存清掉,如图:


缺点:这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying 算法的效率会大大降低。

标记整理算法(Mark-Compact)

结合了以上两个算法,为了避免缺陷而提出。标记清除阶段和 Mark-Sweep 算法相同,最后将存活的对象整理到内存的一端。如图:

分代收集算法

1. 新生代

是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收。新生代又分为 Eden 区、ServivorFrom、ServivorTo 三个区。

1.1. Eden 区

Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden 区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。

1.2. ServivorFrom上一次 GC 的幸存者,作为这一次 GC 的被扫描者。

1.3. ServivorTo保留了一次 MinorGC 过程中的幸存者。

1.4. MinorGC 的过程(复制->清空->互换)MinorGC 采用复制算法。

2.老年代.

在老年代-标记整理算法 因为对象存活率高、没有额外空间对它进行分配

担保, 就必须采用“标记—清除”或“标 记—整理”算法来进行回收,

不必进行内存复制, 且直接腾出空闲内存.

垃圾回收器

●Serial 垃圾收集器(单线程、复制算法)

●ParNew 垃圾收集器(Serial+多线程)

●Parallel

Scavenge 收集器(多线程复制算法、高效)

●Serial Old 收集器(单线程标记整理算法

●Parallel Old 收集器(多线程标记整理算法)

●CMS 收集器(多线程标记清除算法)

●G1

●ZGC?


●1.两个收集器之间有连线,表明它们可以搭配使用。

●2.其中Serial Old作为CMS出现"Concurrent Mode Failure"失败的后备预案。

●3.(红色虚线)由于维护和兼容性测试的成本,再JDK8时将Serial+CMS、ParNew+Serial Old这两个组合声明为废弃,并在JDK9完全取消了这些组合的支持,即移除。

●4.(绿色虚线)JDK14中,弃用Parallel Scavenge+SerialOld组合。删除CMS垃圾回收器。


7种垃圾回收器的区别与特点

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容