性能优化专题(JVM垃圾回收)

eden

-Xms20m -----starting开始的大小即最小
-Xmx200m -----max最大空间
-Xmn20m -----new(新生代的大小)
-XX:(Boolean类型)DisableExplicitGC

  • -XX:-DisableExplicitGC代表关闭
  • -XX:+DisableExplicitGC代表开启

-XX:preBlockSpin=10(数值类型)
Thread Locale Allaction Buffer TLAB

首先申请空间的时候会去eden区去申请,那是不是所有的对象都在eden区分配?答案不是的,大部分对象还有栈上分配都是在eden分配,大对象是直接进入到老年代的,优先去eden去分配空间,最后还是在堆里面分配。

对象去分配的时候,内存规整(持有压缩算法)的话,把对象的地址给指向
在这里插入图片描述再继续申请空间的话,在这里插入图片描述继续移动指针(指针碰撞)。在操作空间的时候会是多个线程操作共享空间,在这里插入图片描述比如这样,就涉及到了一个同步的问题,jvm中用CAS来解决指针激烈碰撞同步问题,二者对象是不会并行存在的在这里插入图片描述这样非常消耗资源的所以开辟了另外一种栈上分配来解决。
在堆里面每个线程都有一个属于自己的TLAB(Thread Local Allcation Buffer)即线程本地分配缓存区。这是一个线程专用的内存分配区域。在这里插入图片描述
如果要分配空间的话,只需要在这个线程单独的空间栈上分配,这样就不存在并发在这里插入图片描述
-XX:+UseTLAB
如果内存不规整的话在这里插入图片描述
则会FreeList来标记哪些空间是空闲的相关详细信息。
多线程情况下,会存在并发,用cas会影响效率,所以jvm还是采用栈上分配的形式来避免过多的这种消耗资源的操作。

survivor

在这里插入图片描述
每一个对象的分配都会在eden区,形式或许有很多种,s0和s1是survivor区,即当eden快满的时候将会触发一次minorGC,通过复制回收算法,不能回收的移到s0区中
对象分配eden
-XX:SurvivorRatio=8
8:1:1的分区:因为对象的生命周期不一样,希望对象能最大限度的不要进入老年代,让其生命周期age能限度的更大,不影响到我们的使用,新生代使用的是MinorGC,而老年代使用的是MajorGC。效率上比MinorGC要慢很多

老年代

大对象
设置该参数决定我们要不要直接进入老年代。单位是B
-XX:PretenureSizeThreshold=3145728
在这里插入图片描述
让其直接进入老年代
长期存活的对象
控制条件-XX:MaxTenuringThreshold=15(默认年龄)
age大于多少的时候就可以进入老年代
动态对象年龄判定
相同年龄所有对象的大小总和 > Survivor空间的一半
空间分配担保机制
新生代的Minor GC之前检查
老年代最大可用连续空间是否 > 新生代所有对象总空间

Minor GC:新生代回收算法
Major GC:老年代回收算法
Full GC:Minor GC + Major GC
垃圾回收器的最终目的是为了减少Ful GC

引用


  • – Object obj = new Object() 判断算法,GC Root可达

  • –内存不足的时候会被回收掉SoftReference,可做缓存使用

  • – 不管空间够不够用,就回收

  • – 弱引用的基础上在引用的时候会被通知到

回收

方法论

算法是演变的过程

标记-清除算法

使用过后的进行标记,清除掉标记的空间
在这里插入图片描述
其效率不高,空间碎片多

复制回收算法

优点实现简单,高效。
缺点空间利用率低
在这里插入图片描述

标记-整理算法

在这里插入图片描述
如果两个都存活,会进行整理,这样没有碎片的存在。
根据其理论基础,会有不同的垃圾回收器

垃圾收集器

在这里插入图片描述

新生代用的是复制回收算法
在这里插入图片描述

Serial

站在椅子上不要动还是边动我边打扫。这里是站在椅子上不要动
在这里插入图片描述
单线程GC处理垃圾回收,用于我们的新生代

ParNew

多个线程处理GC垃圾回收,相较于Serial是多了线程。处理速率更快。用于新生代。
多线程的个数
-XX:ParallelGCThreads=n

Parallel Scavenge(全局)

面向的是吞吐量
吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
关于的是时间上的全局分布。
-XX:MaxGCPauseMillis=n 控制GC的停止时间
-XX:GCTimeRatio=n
-XX:UseAdaptiveSizePolicy

Serial Old

标记整理算法
可以和任何一个新生代产生关联,默认是Serial
Cms备用预案 Concurrent Mode Failure时使用

Parallel Old

标记整理算法
只和Parallel Scavenge结合使用

CMS(并行清理)

常用
标记清除算法
默认的新生代处理器是ParNew
目标是减少回收停顿时间
除了CMS之外,其他所有算法都会整理压缩。
初始标记,STW,标记在GCRoot的一个表(GCRoot直接关联),单线程
并发标记,线程在运行的时候,业务线程也在运行。根据Root去跟踪一下链
重新标记,STW(业务线程停止),并发的往前走,第二阶段的时候业务线程在进行,关系可能产生改变。多线程。
并发清除, 开启用户线程,同时GC线程开始对为标记的区域做清扫。
劣:CPU敏感,吞吐量下降,碎片存在(压缩:-XX:CMSInitiationOccupancyFraction)
当到了某个阶段(Concurrent Mode Failure)就要启动Serial Old
在这里插入图片描述
在FullGc的时候要不要开启压缩-XX:+UseCMSCompactAtFullCollection
间隔FullGC之后压缩一次-XX:CMSFullGCBeforeCompaction 0表示每次都压
显示设置用什么回收算法-XX:+UseConcMarkSweep
在这里插入图片描述
在这里插入图片描述

G1(用的少)

把整个内存空间隔成n个块,每个块的大小1-32M,最多2000个区域

在这里插入图片描述
垃圾回收有两种:一种是Young GC 一种是Old GC
并发标记垃圾回收STW的时候,会有内存压缩的操作。
Garbage first(G1)会优先选择第一块垃圾最多的区域去收集

当一个线程抛出OOM异常后,它所占据的内存资源会全部被释放掉,从而不会影响其他线程的运行。

回收的时间节点

时间点称之为 “Stop The World”----Safepoint,这个时间点在程序中的选定要是太少,那么GC 就要等待太久,要是太多个安全点,那么GC 次数变多,容易引起性能问题,所以安全点的选定基本上是以“是否具有让程序长时间执行的特征”,具有这类的最明显的特征就是指令序列复用,例如方法调用,循环跳转,异常跳转等。
应该如何中断正在执行的线程,当要GC 时所有线程一起停下来吗?
JVM 使用主动式中断( Voluntary Suspension ),当要GC时,仅仅设置一个标志位,让线程自己去主动轮询这个标志,发现中断标志为真时,就自己挂起,轮徐标志的地方和安全点是重合的。

GC日志
1.输出日志
-XX:+PrintGCTimeStamps
-XX:PrintGCDetails
-Xloggc:/home/gc.log
-XX:PrintHeapAtGC
2.日志文件控制
-XX:-UseGCLogFileRotation
-XX:GCLogFileSize=8K
3.怎么看
jdk自带的监控工具
jmap -heap pid 堆的使用情况
jstat -gccause pid time jstat -gccause 256 3000 上一次gc执行的原因
jstack 线程dump
jvisualvm

猜你喜欢

转载自blog.csdn.net/lf1013667686/article/details/86791825