GC垃圾回收机制
gc管理的部分:Java堆(程序计数器、虚拟机栈、本地方法3个区域不需要过多考虑回收的问题)
原因:计数器、虚拟机栈、本地方法3个区域不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了,而java堆和方法区则不一样,一个接口中的多个 实现类需要的内存可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存。
gc判断对象是否存活的算法:
1.引用计数算法
1.引用计数算法
给对象中添加一个引用计数器,当有一个地方引用它时,计数加1,当引用失效时,计数减1;任何时刻计数器为0的对象就是不可能再被使用的。这个算法简单,判定效率 高,但是主流的java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间的相互循环引用
2.可达性分析算法
通过GC Roots的对象作为起始点,从节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连,则此对象不可用
CG Roots对象类型: 虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(Native方法)引用的对象
引用类型: 强引用>软引用>弱引用>虚引用
垃圾回收算法:
1.标记--清除算法
标记清除算法首先标记出需要清除的对象,在标记完成后统一回收需要清除的对象。存在的问题一个是效率问题,标记和清除两个步骤的效率都不高。另一个是空间问题, 清除后会产生不连续的内存碎片
2.赋值算法(年轻代使用)
这个算法将内存空间分为两个相等的部分,一次只使用一半的内存空间。当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一 次清理掉。解决碎片问题,使用效率降低
3.标记-整理算法(老年代使用)
根据老年代的特点,可以使用标记整理算法,标记过程与标记清楚一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理 掉端边界以外的内存
4.分代收集算法
当前商业虚拟机的垃圾收集都是采用分代收集算法,一般把java堆分为新生代和老年代,在新生代中选用复制算法,老年代中使用标记-清理或者标记-整理算法来进行回收
对象在内存中的状态变化:
虚拟机给每个对象定义了对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间,并且年龄对象 设为1。对象在Survivor每熬过一次Minor GC,年龄就加1,当到达默认的15岁,就将会被晋升到老年代中,可通过参数-XX:MaxTenuringThreshold设置进入老年代的岁数