GC

一、判断对象是否存活
1、可达性分析算法
通过一系列的 ‘GC Roots’ 的对象作为起始点,从这些节点出发所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连的时候说明对象不可用。
2、可作为GC ROOT的对象
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中 JNI(即一般说的 Native 方法) 引用的对象
3、四种引用
3.1、强引用
类似于 Object obj = new Object(); 创建的,只要强引用在就不回收。
3.2、软引用
SoftReference 类实现软引用。在系统要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行二次回收。
3.3、 弱引用
WeakReference 类实现弱引用。对象只能生存到下一次垃圾收集之前。在垃圾收集器工作时,无论内存是否足够都会回收掉只被弱引用关联的对象。
3.4、虚引用
PhantomReference 类实现虚引用。无法通过虚引用获取一个对象的实例,为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
对象处于GCROOT不可达后,会根据finalize方法来判断是否要回收

二、GC算法
2.1、标记清除算法(容易产生大量碎片)


GC_第1张图片
image.png

2.2、复制算法
2.3、标记整理算法(该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存)


GC_第2张图片
image.png

2.4、分代收集算法
年轻代采用复制算法,年老代采用标记整理算法
三、GC收集器
CMS收集器:是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是标记清除算法。(缺点:对 CPU 资源敏感、无法收集浮动垃圾、标记 —— 清除 算法带来的空间碎片)
运行步骤:
初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象
并发标记(CMS concurrent mark):进行 GC Roots Tracing
重新标记(CMS remark):修正并发标记期间的变动部分
并发清除(CMS concurrent sweep)


GC_第3张图片
image.png

G1收集器(G1将新生代,老年代的物理空间划分取消了,把堆划分成若干个区域):并行和并发收集器
优点:并行与并发、分代收集、空间整合、可预测停顿
运作步骤:
初始标记(Initial Marking)
并发标记(Concurrent Marking)
最终标记(Final Marking)
筛选回收(Live Data Counting and Evacuation)


GC_第4张图片
image.png
GC_第5张图片
image.png

3.2、G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器。不过,这些区域的一部分包含新生代,新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。老年代也分成很多区域,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。这就意味着,在正常的处理过程中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有cms内存碎片问题的存在了。
在G1中,还有一种特殊的区域,叫Humongous区域。 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。
对象分配策略
TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区
Eden区中分配
Humongous区分配
TLAB为线程本地分配缓冲区,它的目的为了使对象尽可能快的分配出来。如果对象在一个共享的空间中分配,我们需要采用一些同步机制来管理这些空间内的空闲空间指针。在Eden空间中,每一个线程都有一个固定的分区用于分配对象,即一个TLAB。分配对象时,线程之间不再需要进行任何的同步。对TLAB空间中无法分配的对象,JVM会尝试在Eden空间中进行分配。如果Eden空间无法容纳该对象,就只能在老年代中进行分配空间。

G1 GC模式:
G1 young GC
Young GC主要是对Eden区进行GC,它在Eden空间耗尽时会被触发。在这种情况下,Eden空间的数据移动到Survivor空间中,如果Survivor空间不够,Eden空间的部分数据会直接晋升到年老代空间。Survivor区的数据移动到新的Survivor区中,也有部分数据晋升到老年代空间中。最终Eden空间的数据为空,GC停止工作,应用线程继续执行。
G1 Mixed GC

常用JVM定位命令
jsta(类加载情况,GC情况,JVM运行时数据区情况)

Option Displays Ex
class 用于查看类加载情况的统计 jstat -class pid:显示加载class的数量,及所占空间等信息。
compiler 查看HotSpot中即时编译器编译情况的统计 jstat -compiler pid:显示VM实时编译的数量等信息。
gc 查看JVM中堆的垃圾收集情况的统计 jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
gccapacity 查看新生代、老生代及持久代的存储容量情况 jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小
gccause 查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。 jstat -gccause:显示gc原因
gcnew 查看新生代垃圾收集的情况 jstat -gcnew pid:new对象的信息
gcnewcapacity 用于查看新生代的存储容量情况 jstat -gcnewcapacity pid:new对象的信息及其占用量
gcold 用于查看老生代及持久代发生GC的情况 jstat -gcold pid:old对象的信息
gcoldcapacity 用于查看老生代的容量 jstat -gcoldcapacity pid:old对象的信息及其占用量
gcpermcapacity 用于查看持久代的容量 jstat -gcpermcapacity pid: perm对象的信息及其占用量
gcutil 查看新生代、老生代及持代垃圾收集的情况 jstat -util pid:统计gc信息统计
printcompilation HotSpot编译方法的统计 jstat -printcompilation pid:当前VM执行的信息

JMAP :内存映射
jstack:java堆栈跟踪工具
jhat:jvm堆快照分析工具

内存高和CPU高的处理

四、CPU的定位
找到最耗CPU的进程:Top -Hp pid
printf “%xn” 15332 // 转换16进制(转换后为0x3be4)
jstack pid |grep 'threadPid' -C5 --color jstack pid |grep '0x3be4' -C5 --color

五、OOM :内存泄漏
排查资源申请 :jmap -heap 11869
排查GC:jstat -gcutil 11938 1000 每秒输出一次gc的分代内存分配情况,以及gc时间
查找最费内存的对象:
jmap -dump:format=b,file=/tmp/dump.dat 11869
pstree: 显示进程的关系
netstat :查看网络连接数
Athas的使用
六、常见JVM调优以及参数
-XX:+PrintGC:开启打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 详细信息。

七、堆大小的大小最佳实践
GC打印
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename

八、并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数
-XX:MaxGCPauseMillis=n:设置并行收集最大的暂停时间(如果到这个时间了,垃圾回收器依然没有回收完,也会停止回收)
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为:1/(1+n)
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况
-XX:ParallelGCThreads=n:设置并发收集器年轻代手机方式为并行收集时,使用的CPU数。并行收集线程数

你可能感兴趣的:(GC)