JVM 调优理论知识:垃圾回收。常见垃圾回收器、GC算法。PC、PN、CMS、PO、G1、ZGC,JVM GC算法

为什么java需要性能调优?

防止内存被撑爆,回收掉不被使用的对象。让有限的空间做无限的可能。

为什么java需要采用分代回收思想?

让不被使用或使用较少的对象,尽可能在年轻代中被回收,减少full GC,减少STW的时间,提高性能。

熟悉GC常用算法,熟悉常见垃圾收集器,具有实际JVM调优实战经验

garbage : 垃圾

什么是garbage?没有被引用的对象都是垃圾 garbage

how to find a garbage  如何找到垃圾

1.reference count  引用计数

rc 不能解决的问题: 循环引用。例如 A引用B,B引用C,C引用A.

2.root searching  根可达算法。根对象: 线程栈变量、静态变量、常量池、JNI指针

扫描二维码关注公众号,回复: 11373504 查看本文章

GC algorithms   : GC 算法

1. Mark-Sweep ( 标记清除 )

2.Copying (拷贝)

3. Mark-Compact (标记压缩)

Mark-Sweep ( 标记清除 ):算法相对简单,在存活对象比较多的情况下效率较高。两遍扫描,效率较低,容易产生碎片。

不适合Eden 区

Copying:适用于存活对象较少的情况,只扫描一次,效率提高,没有碎片。 空间浪费,移动复制对象,需要调整对象引用。

适合于 Eden 区

 

Mark-Compact (标记压缩):不会产生碎片,方便对象分配,不会产生内存减半。需要扫描两次,需要移动对象,效率偏低

 一个对象如果 stack(栈)上分配足够,如果扔不下,直接扔到eden区。

 对象什么时候进入老年代

Eden区+s1 放到s2 ,如果超过50%,则优先将年龄大的对象放入到老年代。

对象分配过程

 1.new 对象,判断对象在stack(栈)里面是否放的下,放的下就放,用完销毁,结束。

2.  栈分配不下,看下大小(可通过参数设置),比较大,直接进入old区。进行了FGC才会结束。

3. 如果不够大,会进入到TLAB,即进入Eden区。

4. 如果被GC清除,则结束。如果没被GC清除,则进入s1。

5. s1再进行清除。如果年龄够了,则进入到老年代,不够则进入s2,s2再进行gc清除,没被清除进入到s1,知道年龄足够进入老年代

6.当遭遇老年代FGC时被清除,则end。

常见垃圾回收器

1. JDK诞生 Serial追随 提高效率,诞生了PS,为了配合CMS,诞生了PN,
CMS是1.4版本后期引入,CMS是里程碑式的GC,它开启了并发回收的过程,
但是CMS毛病较多,因此目前任何一个JDK版本默认不是CMS
   并发垃圾回收是因为无法忍受STW
2. Serial 年轻代 串行回收
3. PS 年轻代 并行回收
4. ParNew 年轻代 配合CMS的并行回收
5. SerialOld  单线程
6. ParallelOld
7. ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)
   CMS问题比较多,所以现在没有一个版本默认是CMS,只能手工指定
   CMS既然是MarkSweep,就一定会有碎片化的问题,碎片到达一定程度,
CMS的老年代分配对象分配不下的时候,使用SerialOld 进行老年代回收
   想象一下:
   PS + PO -> 加内存 换垃圾回收器 -> PN + CMS + SerialOld(几个小时 - 几天的STW)
   几十个G的内存,单线程回收 -> G1 + FGC 几十个G -> 上T内存的服务器 ZGC
   算法:三色标记 + Incremental Update
8. G1(10ms)
   算法:三色标记 + SATB
9. ZGC (1ms) PK C++
   算法:ColoredPointers(颜色指针) + LoadBarrier
10. Shenandoah
    算法:ColoredPointers(颜色指针) + WriteBarrier
11. Eplison
12. 垃圾收集器跟内存大小的关系
    1. Serial 几十兆
    2. PS 上百兆 - 几个G
    3. CMS - 20G
    4. G1 - 上百G
    5. ZGC - 4T - 16T(JDK13)

1.8默认的垃圾回收:PS + ParallelOld

常用组合:  serial + serial old、parallel scavenge + parallel old 、parnew + cms。

STW : stop-the-world 。停止一切

常用垃圾回收器图、JVM内存分代模型(用于分代垃圾回收算法)

查看JVM默认的垃圾回收器

cmd命令: java -XX:+PrintCommandLineFlags -version

serial (复制算法) + serial old(标记-整理算法)  单线程回收。及除垃圾回收器工作外,其它线程都暂停。

serial old 同serial ,也是单线程的,只不过用在老年代

 

PS:parallel (并行)scavenge (复制算法)  多线程同时清理

parallel old(标记-整理算法

parnew(复制算法)  parallel Scavenge的新版本,但是可以配合 CMS使用。例如:cms 某个特定阶段时 ,parnew可以同时运行。

parnew 是 parallel Scavenge的新版本,为的是和cms配合,对cms的算法提供了很好的支持。

CMS: concurrent mark sweep  (标记-清除

concurrent(并发)。应用可以一边工作,垃圾回收器可以一边进行。

cms 清理的4个阶段:

1. 初始标记 ,只标记根对象。STW过程。 -- initial mark

2. 并发标记, 并发标记可以和应用程序同时运行。 -- concurrent mark

3. 重新标记,对并发标记过程中产生的垃圾进行标记,STW过程。 -- remark

4. 并发清理,进行垃圾清理。 -- concurrent sweep

老年代分配不下了久会促发 cms

cms缺点:

1. Memory Fragmentation   内存碎片化

   > -XX:+UseCMSCompactAtFullCollection
   > -XX:CMSFullGCsBeforeCompaction 默认为0 指的是经过多少次FGC才进行压缩
   

2. Floating Garbage  浮动垃圾

   > Concurrent Mode Failure
   > 产生:if the concurrent collector is unable to finish reclaiming the unreachable 
objects before the tenured generation fills up, 
or if an allocation cannot be satisfiedwith the available free space blocks
 in the tenured generation, then theapplication is paused and the collection 
is completed with all the applicationthreads stopped
   >
   > 解决方案:降低触发CMS的阈值。-XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,
让CMS保持老年代足够的空间. 默认设置为92%产生FGC,
可以通过降低预值例如:68%、 50%等等 来保证有足够的空间进行分配
   >
  > PromotionFailed 内存分配错误
  > 解决方案类似,保持老年代有足够的空间

浮动垃圾和内存碎片化都会导致从年轻代过来的对象会找不到可足够分配的空间,需要使用 serial old 进行清理, 造成STW 时间较长。

Full GC : 整体内存。 触发条件:老年代内存不够就会触发。默认PS + PO,或者PN+CMS


 

猜你喜欢

转载自blog.csdn.net/dandanforgetlove/article/details/106102225