JVM的垃圾回收主要发生在堆内存中,堆内存分为新生代,老年代,新生代分为伊甸园区(Eden),幸存者区1(S0),幸存者区2(S1)
大部分情况下(当对象很大的时候,直接进入老年代),对象首先都会在Eden分配,在一次新生代垃圾回收之后,如果对象还存在的话,就会进入S0或者S1,并且对象的年龄会加1,经历这次GC后,Eden和From区会被清空,这个时候,from和to会调换位置,minor Gc一直重复这个过程,最后超过15岁的时候,对象就会进入老年代。
为什么大对象要直接进入老年代呢?
为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。
针对 HotSpot VM 的实现,它里面的 GC 其实准确分类只有两大种:
部分收集 (Partial GC):
- 新生代收集(Minor GC / Young GC):只对新生代进行垃圾收集;
- 老年代收集(Major GC / Old GC):只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代整堆收集;
- 混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集。
整堆收集 (Full GC):收集整个 Java 堆和方法区。
什么是空间分配担保机制?
进行minor GC之前要先检查老年代是否有足够空间去接受新生代存活下来的对象
JDK 6 Update 24之后的规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行 Minor GC,否则将进行 Full GC。
如何判断对象已经死亡?
引用计数器法:给对象添加一个引用计数器,用的时候就+1,引用失效的时候就-1,当为0的时候就说明失效了。
缺点:解决不了互相引用的问题,
除了对象 objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为 0,于是引用计数算法无法通知 GC 回收器回收他们。
2.2 可达性分析算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
可作为 GC Roots 的对象包括下面几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 本地方法栈(Native 方法)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 所有被同步锁持有的对象
引用:
JDK1.2以后,引用分为了强引用,软引用,弱引用,虚引用
强引用:垃圾回收绝对不会回收它。
弱引用:空间足就不回收,空间不足就回收
软引用:一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用:并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。