-
HotSpot JVM 架构图
截图.png
垃圾回收介绍(Garbage Collection,GC),来源
Automatic garbage collection is the process of looking at heap memory, identifying which objects are in use and which are not, and deleting the unused objects. An in use object, or a referenced object, means that some part of your program still maintains a pointer to that object. An unused object, or unreferenced object, is no longer referenced by any part of your program. So the memory used by an unreferenced object can be reclaimed.
- 判断对象生死
怎样判断一个对象是否是垃圾,即怎样断定一个对象的生死。最常见的两种方法:引用计数,可达性分析-根搜索算法
1.引用计数
即每个对象被其他对象引用时会有几个计数标记,每被引用一次则计数+1,当引用计数为0时,表明该对象成为垃圾不在存活。该方法实现简单容易理解,但是改方法无法解决对象间循环引用的情况,当多个对象循环引用即使所有对象之后不被再使用,对象的引用计数也不会为0。
2.可达性分析,根搜索算法
思路就是通过一系列的“GC Roots”,也就是根对象作为起始节点集合,从根节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为引用链,如果某个对象到GC Roots间没有任何引用链相连,则改对象已"死亡"
1.虚拟机栈(栈帧中的本地变量表)中引用的对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈中JNI(即一般说的Native方法)引用的对象
在程序运行过程中对象的引用关系一直在变化,会出现漏标或错标的问题。
最简单的一种方式是挂起应用程序stw(stop the world),然后进行根搜索并进行标记对象生死,但是在这种情况下(stw)挂起应用程序进行垃圾标记和回收必然会影响程序响应时间,引起卡顿等现象。另一种方式是把标记和回收分多个阶段进行:
1.初始标记:扫描gc root,少快-stw
2.并发标记:扫描gc root 以为的对象,多慢,会出现漏标和错标等问题
3.重新标记:扫描并发标记过程中出现的漏标错标对象,少快-stw
4.并发清理
- 并发标记-三色标记法
三色标记发顾名思义对象在并发标记过程中有三种状态或三种颜色,
黑:表示对象已经被垃圾回收器访问过,且这个对象的所有引用都已经扫描过
灰:表示对象已经被垃圾回收器访问过,但这个对象至少存在一个引用还没有被扫描过
白:表示对象尚未被垃圾回收器访问过
在标记完成阶段,只有黑色和白色状态,灰色是中间状态。黑色表示存活对象
,白色表示死亡对象
截图 (3).png
并发标记会有两种后果:
1.原本消亡的对象标记为存活,这不是好事,但是不会带来严重的后果,无非会产生一定的浮动垃圾,可以容忍,下次垃圾回收是清理即可
如图,在并发标记完成时会有一些对象被标记为黑色(存活),但实际是已经已经不存活的对象。如在表发过程中,虽然B之后的对象被标记为黑色,但在标记完后A断开了B之间的引用关系。
2.原本存活的对象标记为消亡,程序正在使用的对象却被误标进行了垃圾清理,这会对应用程序带来灾难性的后果
在标记过程中,原本B到D的引用关系,修改为了A与D之间的引用关系,因为A已经被标记为了黑色,A到D的引用不会再被扫描,则D对象一直为白色,则会被误以为是死亡对象而被错误回收。
对象被误标记为白色对象的情况需要满足两个条件:
Wilson证明了,当且仅当以下两个条件同时满足时,会产生"对象消失"的问题,原来应该是黑色的对象被误标为了白色
条件一:赋值器插入了一条或者多条从黑色对象到白色对象的新引用。
条件二:赋值器删除了全部从灰色对象到该白色对象的直接或间接引用
所以要解决并发标记中对象消失,就需要破坏上面的任意条件,于是产生了两种解决方案,增量更新和原始快照
1.增量更新
增量更新破坏第一个条件,当有赋值器插入了一条或者多条从黑色对象到白色对象的新引用时,黑色对象被重新标记为灰色对象,在重新标记时重新扫描。
2.原始快照
原始快照破坏第二个条件,赋值器删除了全部从灰色对象到该白色对象的直接或间接引用