包括:
一. 垃圾回收基本概念
二. GC日志
一. 垃圾回收基本概念
在JVM 中,最需要进行回收的地方就是 JVM 方法区 和 JVM 堆。
1.1 可达性分析算法
回收的时候,主要是根据可达性分析算法。如果一个对象不可达,那么就是可以回收的;如果一个对象可达,那么这个对象就不会被回收。那么,对于可达性分析算法,它是通过一系列称为 "GC Roots" 的对象作为起始点,当一个对象到GC Root 没有任何引用链相接的时候,则证明这个对象不可用,即可以进行回收。如下图:
一. 垃圾回收基本概念
二. GC日志
一. 垃圾回收基本概念
在JVM 中,最需要进行回收的地方就是 JVM 方法区 和 JVM 堆。
1.1 可达性分析算法
回收的时候,主要是根据可达性分析算法。如果一个对象不可达,那么就是可以回收的;如果一个对象可达,那么这个对象就不会被回收。那么,对于可达性分析算法,它是通过一系列称为 "GC Roots" 的对象作为起始点,当一个对象到GC Root 没有任何引用链相接的时候,则证明这个对象不可用,即可以进行回收。如下图:
这个GC Root 对象可以是一些静态的对象,Java方法的local变量或参数, native 方法引用的对象,活着的线程。
Ps:
有些资料认为 垃圾回收根据引用计数法,但是在本人的测试中结果是用可达性分析算法。证明如下:
有如下程序(Student 对象1 -->Student对象2 -->Student对象3):
public class Test {
public static void main(String[] args) throws InterruptedException {
Student stu = new Student(new Student(new Student()));
Thread.sleep(15 * 1000);
stu = null;
Thread.sleep(100 * 1000);
}
}
class Student {
private String name;
private Student stu;
public Student() {}
public Student(Student stu){this.stu = stu;};
}
那么,结果是一开始如下图确实有3个实例,但是在stu = null 之后,实例就没有,已经被GC回收。所以说不是程序计数法来判断是否回收:
1.2 回收方式
回收方式会有多种,比如说 标记-清除法;复制算法;标记-整理法。
复制算法:JVM 的堆内存会分为新生代和老年代,新生代主要就是采用复制算法。复制算法的主要概念是:把内存分为AB两块,每次只是使用其中一块,当A内存使用完之后,就把A 中还存活的对象复制到另外一块内存中去。这样的有点就是不需要考虑内存碎片的问题。缺点就是内存减半,代价太高。但是在新生代的实际应用中,不会55分,而是按8:1:1 的比例,分为1个Eden区 和两个Survivor 区域。这就是复制算法。
标记整理法:JVM的老年代就是用 标记整理法,也就是说,当需要GC 的时候,会先标记,然后把存活的对象都移到一端。
二. GC日志
图1
图2
Full GC 信息与 Minor GC 的信息是相似的,这里就不一个一个的画出来了。
从 Full GC 信息可知,新生代可用的内存大小约为 18M,则新生代实际分配得到的内存空间约为 20M(为什么是 20M? 请继续看下面…)。老年代分得的内存大小约为 42M,堆的可用内存的大小约为 60M。可以计算出: 18432K ( 新生代可用空间 ) + 42112K ( 老年代空间 ) = 60544K ( 堆的可用空间 )
新生代约占堆大小的 1/3,老年代约占堆大小的 2/3。也可以看出,GC 对新生代的回收比较乐观,而对老年代以及方法区的回收并不明显或者说不及新生代。并且在这里 Full GC 耗时是 Minor GC 的 22.89 倍。
总结:
- 主要回收场所:JVM方法区,JVM方法栈。
- 回收方式: 新生代(复制算法),老年代(标记整理法)。
- 根据Young / Old 判断是新生代还是老年代的 GC,然后就是给出 Young / Old ,整个堆内存 GC 前后的大小。