Java-垃圾回收
1、 Java GC堆内存分配。
2、晋升年龄(默认是15岁,Hotspot是动态年龄判定,遍历所有对象,按照年龄从小到大对其占用的大小进行累积,当累积到某个年龄超过了survivor的50%取这个年龄为晋升阈值。)
GCRoot对象
1、虚拟机方法栈(栈帧中的本地变量表)中的引用变量。
2、本地方法栈中的引用变量。
3、方法区中静态属性的引用对象。
4、方法区中常量引用的对象。
5、所有被同步锁持有的对象。
方法区中存储了:1、类信息(包括了JVM加载类型:类class、接口interface、枚举enum)、直接父类的完整有效名称、类型修饰符2、成员变量信息3、静态变量4、运行时常量池:各种字面量和类型等引用。
加入eden和from都有对象,那么将这两个地方的对象都复制到to区,然后交换from和to。
GC规模
1、MinorGC发生在新生代的垃圾回收,暂停时间短
2、MixedGC新生代+老年代部分区域的垃圾回收,G1收集器特有
3、FullGC新生代+老年代 完整垃圾回收,暂停时间长,尽力避免
1.1对象优先在eden区分配
大多数情况下,对象在新生代中eden区分配,当eden没有足够多空间分配的时候,虚拟机将发起一次MinorGC
针对HotSpotVM的实现,里面的GC主要分为两大种:
部分收集(PartialGC)
1、新生代收集(MinorGC/Younggc):只对新生代进行垃圾收集
2、老年代收集(MajorGC/OldGC):只对老年代进行垃圾回收,需要注意的是MajorGC在有语境中也用于指代整堆收集
3、混合收集(MixedGC):对整个新生代和部分老年代进行垃圾收集
整堆收集(Full GC):对整个JAVA堆和方法区收集。
ConcurrentMarkSweepGC(CMS)
1、old并发标记,重新标记时需要STW,并发清除
2、failback full gc
3、缺点会有内存碎片
4、注重响应时间
二、垃圾回收器
7种垃圾收集器与垃圾分代之间的关系
Parallel GC(吞吐量优先 )
1、eden内存不足发生MinorGC,标记复制STW(不会有碎片)
2、old内存不足发生FullGC,标记整理STW(不会有碎片),暂停时间更长,因为要完整的回收。
3、注重吞吐量。(比如消息队列的消息传过来后涉及大量的计算,而不是立即与用户做交互,工资支付,科学计算等)
在吞吐量优先的场景,paralle收集器与parallelold收集器的组合,在server模式下内存回收性能不错。二者是相互激活的
可以设置的参数
最大停止时间、使用自适应调优策略。
互联网请求尽量不要暂停。
大量计算响应时间,响应时间久一点,但是整体上时间短就行。
JDK8 默认使用的是Parallel Scavenge
垃圾回收器:
ConcurrentMarkSweep GC (CMS)(用的三色标记算法 黑灰白,标记两次,因为在第一次标记的完后,用户线程可能更改引用,然后进行第二次标记,第二次标记不会被清理,只有第二次cms才会清理)
1、old并发标记,重新标记时需要STW,并发清除 (会存在内存碎片)
2、Failback full gc
3、注重响应时间。 并发导致线程去做垃圾对象标记,所以吞吐量会变低。
弊端:
并发标记的时候,用户线程将有些标记为黑色的对象,变成灰色,但是下次重新标记会不扫描他们,导致产生浮动垃圾。
参数使用 手动指定cms收集器, -XX:+useConcMarkSweepGC、设置CMS线程数。
jdk9以后 G1GC(以后默认的垃圾回收器,在保证吞吐量优先的情况下,降低停顿时间)
局部是复制算法,在整体是标记整理算法。
优势:
1、并行和并发
2、
3、
1、并发与并行:在多核环境下能够使用多个CPU来缩短STW的停顿时间。部分其他收集器原本需要停顿java线程,执行GC动作,G1收集器仍然可以通过并发方式让java继续执行。
2、分代收集:虽然G1可以不需要其他收集器就能独立管理整个GC堆,但是还是保留了分代回收
3、空间整合:与CMS的“标记-清理”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器。从局部看是标记复制
4、可预测的停顿:G1的优势,降低停顿时间是CMS和G1共同关注的,但G1追求停顿的外,还可以建立可预测的时间模型,使使用者明确指定长度M毫秒时间内。
垃圾回收步骤:
1、初始标记
2、并发回收
3、最终标记
4、筛选回收
G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优选选择回收价值最大的Region。这种Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限时间内尽可能收集更多内存。
优势:
eden区回收复制到Survivor区
从经验来说,小内存应用上CMS的表现大概率会高于G1,G1在大内存应用上发挥起优势。
CMS需要额外的空间,额外负载,rset来记忆,避免全局扫描。
G1回收期场景操作步骤
1、开启G1垃圾收集器
2、设置堆的最大内存
3、设置最大的停顿时间
回收过程:
1、年轻代GC minor gc
2、老年代并发标记
3、混合回收mixed gc(全部新生代和部分老年代,部分老年代根据回收价值绝对那个先回收)
如果需要针对GC评估失败,提供一种失败保护机制,即强力回收。
G1垃圾回收期具体过程:
1、
2、
1、响应时间与吞吐量兼顾
2、划分多个区域每个区域可以充当eden survivor humongous
3、新生代回收:eden内存不足,标记复制 stw
4、并发标记:old并发标记,重新标记需要stw
5、混合收集:并发标记完成,开始混合收集,参与复制的eden、survivor、old,其中old会根据暂停时间目标,选择回收价值高的区域,复制时STW
6、failback full gc
Serial回收器:串行回收
最基本最老的收集器。采用的复制算法、串行回收和stw机制进行内存回收。
总结:
这种垃圾收集器,现在不用串行的了,而且在限定单核cpu才可以用,对于交互性强的应用而言,这种垃圾收集器是不能接收的。一般在javaweb应用程序中是不会采用串行垃圾收集器的。
ParNew回收期
除了收集器采用的是并行回收的方式以外,两款垃圾收集器几乎没有任何区别。parnew同样也是采用复制算法,“stop the world”机制
parnew 是很多jvm运行在server模式下新生代的默认垃圾收集器。
小结:
如果想要最小化地使用内存和并行开销,选Serial GC;
如果想要最大化地应用程序,选Parallel GC
如果想要最小化GC中断或者停顿时间,选CMS GC
判断对象死亡:
1.1引用计数法:(目前基本不用了)
如果对象有引用就不是死亡,但是会出现循环引用的现象。回收不了
1.2可达性分析算法
基本思想:通过一系列的GCRoots的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到GC Roots每页任何引用链引用的话,则需要回收
那些对象可以作为GC Roots呢?
1、虚拟机栈(栈帧的本地变量表)中的引用对象。
2、本地方法栈(Native 方法)中引用的对象
3、方法区中类静态属性引用的对象
4、方法区中常量引用的对象
5、所有被同步锁持有的对象
三、对象可以被回收,就一定可以被回收吗?
即使在可达性分析法中不可达的对象,也并非是非死不可的,因为可能处于缓刑状态,真正宣告一个对象死亡,
至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行筛选,筛选的条件是次对象是是否有必要
执行finalize的方法。当对象没有覆盖finalize方法,或者finalize方法已经被虚拟机调用过的时候,虚拟机将这两种情况视为没有必要执行。
被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立了联系,否则就会真的被回收。
finalize方法弊端(每个类都有finalizer,它不能被直接调用,而被jvm在适当的时候调用,作为一种收尾机制):
1、行为不稳定
2、降低性能
3、可移植性低
(使用finalizer最严重的缺点是不能保证被执行,一个对象变得不可达开始,一直到该对象被jvm终结,过程中时间是未知的。当一个类提供了finalizer,会查看finalizer队列是否很多实例等待被终结。
面试题:说说GC和分代回收算法
GC目的在与实现无用对象内存自动释放,减少内存碎片、加快分配速度。
GC要点:
1、回收区域是堆内存,不包括虚拟机栈,在方法调用结束会自动释放方法占用的内存
2、判断无用对象,使用可达性分析算法,三色标记法标记存活对象,回收未标记的对象
3、GC具体的实现称为垃圾回收器(G1,CMS,PC)
4、GC大都采用分代回收思想,理论依据大部分朝生夕灭,用完立刻就会回收,另有少部分对象会长时间存活,
每次很难回收,根据这类对象特性分为新生代和老年代,不同区域回收策略不同。
5、根据GC规模可以分为MinorGC,MixedGC,Full GC(老年代不足)
三色标记与并发漏标问题
1、用三种颜色记录对象的标记状态
1.1 黑色-已标记(沿着根对象的引用链找到了这个对象,并且这个对象内部其他引用都处理完了)
1.2 灰色-标记中(沿着根对象的引用链找到了这个对象,但是这个对象内部其他引用未被处理)
1.3 白色-未被标记(未被处理)
三色标记与并发漏标问题
产生漏标问题-记录标记过程中的变化
解决方案:
1、increment update
1.1只要发生了赋值,被赋值的对象就 会被记录(变为灰色)
2、Snapshot at the beginning satb
2.1新对象会被记录
2.2被删除引用关系的对象也会被记录
评估GC的性能指标
1、吞吐量 a/(a+b)
2、垃圾收集开销:b/(a+b)
3、暂停时间:执行垃圾收集时,程序工作被暂停的时间。
4、收集频率:相对于应用程序执行,收集操作发生的频率。 (频率低可能会造成暂停时间长,频率高,暂停时间短)
5、内存占用:Java堆区所占的内存大小
6、快速:一个对象从诞生到回收经历的时间。
标记的这个三个构成了“不可能三角”。
主要关注(吞吐量、暂停时间)
高吞吐量的应用程序有更长的时间基准,快速响应是不必考虑的。
垃圾回收器总结:
Serial=>parallel并行=>cms(并发)=>G1=>ZGC