Java垃圾回收机制——底层逻辑
堆中的对象是持久存储的,那么内存区域是有限的;因此不必要的数据肯定要定期清理,且为了保证内存的规整要整理内存碎片,那么什么是不必要的数据呢?那些永远不可能被访问到的数据就是不必要的数据,java中自动内存管理就是因为如此设计,程序员手动不需要释放内存,一切均有垃圾回收器做判断
Java垃圾回收机制——判断算法
引用计数法:给对象中添加一个引用计数器,每当有 一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;但无法解决循环引用的其他,比如两个对象中的变量相互引用,但这个对象实际不可达就不会被回收;
可达性分析:利用GCRoot作为起点,向下搜索经过的所有引用链中存在的对象那么该对象可达,标记一下;反之就不可达!可达分分析过后标记一次,这个时候被标记的对象会进入F-Quend队列中;然后Finalizer线程去负责执行,这个时候可以强行建立引用拯救对象!
GcRoot:
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象
引用类型
强引用:正常建立引用,永远不会被回收的对象;
软引用:利用SoftReference封装,内存溢出时立即回收的对象;
弱引用:利用WeakReference封装,下一次垃圾回收时立即回收的对象;
虚引用:利用PhantomReference类封装,回收前收到系统通知,但是该引用无法获得实例
枚举根节点:
如果每次回收都需要进行可达性分析,那么这个时间成本太大;所以利用OopMap,记录引用关系可以直接得到所有可达引用;
保守式GC:JVM开始从一些已知位置(例如说JVM栈)开始扫描内存,扫描的时候每看到一个数字就看看它“像不像是一个指向GC堆中的指针”
会有部分对象本来应该已经死了,但有疑似指针指向它们,使它们逃过GC的收集
准确式GC:GC回收时,进入安全点的线程,对栈上的内存进行扫描,看看哪些位置存储了 Reference 类型。如果发现某个位置确实存的是 Reference 类型,就意味着它所引用的对象这一次不能被回收。每一个方法会销毁引用或创建引用,最后这个对象的引用为0就会被回收!
RememberedSet日志:“老年代对象引用新生代对象”这种关系,会在引用关系发生时,在新生代边上专门开辟一块空间记录下来,这就是 RememberedSet
抢占式中断:GC回收时,先中断所有,再放行没到安全点的线程到了再中断他;
主动式中断:GC回收时,每个线程轮询标志,标志位true则自行到安全点中断;
安全区:
安全区域是指在一段代码片段之中,引用关系不会发生变化
在线程执行到Safe Region中的代码时,首先标识自己已经进入了Safe Region;
在线程要离 开Safe Region时,它要检查系统是否已经完成了根节点枚举(或者是整个GC过程),如果完
成了,那线程就继续执行,否则它就必须等待直到收到可以安全离开Safe Region的信号为
止
绝对持久对象:线程的内或方法内生成的对象需要被持久层所引用
短暂需要对象:此次栈中存储的引用,没执行完就不要回收;
Java垃圾回收机制——区域划分
【区域划分】
to区:幸存者审批后再次幸存临时栖息地,回收后from区存活的的对象会被进入这里,但是回收前会进入form区;
Form区:幸存者升级和死亡的地方;
Eden区:朝生夕死,然后进入form-to轮回;
【回收前后】
【回收前:清空to区】回收前将所有对象送回From(保存To区一直是空的)
【回收后:存活移动】
Eden:存活送入From区
From:存活送入to区(来自Eden或清空后的to)
to:是空的!
【调优】
新老总体比例: –XX:NewRatio
复制存活比例: –XX:SurvivorRatio
Ps:我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了
Java垃圾回收机制——回收算法
Java垃圾回收机制——回收类型
Minor GC 是清理年轻代
Major GC 是清理永久代
Full GC 是清理整个堆空间—包括年轻代和永久代
并行(Parallel):多条垃圾收集线程并行工作,而用户线程仍处于等待状态
并发(Concurrent):垃圾收集线程与用户线程一段时间内同时工作(交替执行)这样在扫描到JNI方法的时候就不需要扫描它的栈帧了——只要扫描句柄表就可以得到所有从JNI方法能访问到的GC堆里的对象
Java垃圾回收机制——回收器