线上服务器因为内存溢出导致服务器假死,部分请求通过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种垃圾回收器的区别与特点