Java垃圾回收机制

/ 0评 / 0

垃圾回收机制

对象创建过程

对象内存分布

对象的访问

对象回收算法

如下这些对象就可以作为GC Roots对象:

1、虚拟机栈中引用的对象(参数,局部变量等)

2、方法区中类静态变量

3、方法区中常量引用的对象

4、本地方法栈中引用的对象

5、被同步锁(synchronized)持有的对象

finalize方法

引用类型

对于强引用,我们平时在编写代码时经常会用到。而对于其他三种类型的引用,使用得最多的就是软引用和弱引用,这2种既有相似之处又有区别。它们都是用来描述非必需对象的,但是被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。针对上面的特性,软引用适合用来进行缓存,当内存不够时能让JVM回收内存,弱引用能用来在回调函数中防止内存泄露

因为回调函数往往是匿名内部类,隐式保存有对外部类的引用,所以如果回调函数是在另一个线程里面被回调,而这时如果需要回收外部类,那么就会内存泄露,因为匿名内部类保存有对外部类的强引用。

堆内存分布

堆被划分成两部分:新生代和老年代,新生代和老年代比值为1:2,这个比例并不是唯一的,我们可以可以通过参数 –XX:NewRatio按照具体的场景来指定。

新生代又可以分为 Eden区Survivor区,而Survivor区又可以分为FromSurvivorToSurvivor,默认比值为8:1:1

对象分配策略

其实Java中的对象并不是全部分配在堆内存区域,也可能分配在栈中。一个对象创建后的分配顺序如下:

1、尝试进行栈上分配(线程私有小对象,对象无逃逸,并且支持标量替换),栈上分配的对象会随着方法结束栈帧弹出而消亡,无需等到GC去清理;

2、栈上分配失败,如果是大对象,则直接分配到堆中Old区;

3、如果是小对象,优先进行线程私有本地分配(Thread Local Allocation Buff,文末解释);

4、线程私有本地分配失败,则分配在堆中Young区中的Eden区。

涉及点:

Thread Local Allocation Buff,简称 TLAB,线程私有本地分配。在Eden区中,由于空间是线程共享,会导致多个线程同时去竞争Eden区中位置而降低效率。为了减少这种情况,每个线程会在Eden区中获取一块私有空间(默认1%,JVM参数可调),线程上的私有小对象会优先分配到这里,避免多个线程同时竞争一个位置,提高效率。TLAB也是位于Eden区中。

验证,JVM添加启动参数-XX:-DoEscapeAnalysis -XX:+PrintGC,禁止对象分配在堆上,并且打印GC

public class Test {

    public static void main(String[] args) {
        long b = System.currentTimeMillis();
        for (int i = 0; i < 5000000; i++) {
            test();
        }
        System.out.println(System.currentTimeMillis() - b);
    }

    private static void test() {
        new String("233333");
    }
}

//-静止分配在堆上打印
[GC (Allocation Failure)  65536K->616K(251392K), 0.0007247 secs]
52
//允许分配在堆上打印
4

垃圾回收算法

GC 复制算法(Copying GC)

通过将内存分为两个空间,在垃圾回收是将空间1的活动对象,直接复制到空间2中,然后全部回收掉空间1的对象

改进版本:Appel式回收

新生代分为一块较大的Eden空间和两块较小的 Survivor空间,每次分配内存只使用Eden和其中一块Survivor,三个区域,Eden,From,To

标记-清除算法(Mark-Sweep)

标记阶段清除阶段构成。在标记阶段会把所有的活动对象都做上标记,然后在清除阶段会把没有标记的对象,也就是非活动对象回收

标记-整理算法(Mark-Compact)

两个阶段:标记和整理,在标记阶段会把所有的活动对象都做上标记,整理阶段将对象按顺序排列

常见垃圾收集器

HotSpot虚拟机所有的垃圾收集器如下图

上面有7种收集器,分为部分,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。

收集器 收集对象和算法 收集器类型
Serial 新生代,复制算法 单线程
ParNew 新生代,复制算法 并行的多线程 收集器
Parallel Scavenge 新生代,复制算法 并行的多线程 收集器
收集器 收集对象和算法 收集器类型
Serial Old 老年代,标记整理 算法 单线程
Parallel Old 老年代,标记整理 算法 并行的多线程收集器
CMS 老年代,标记清除 算法 并行与并发收 集器
G1 跨新生代和老年代; 标记整理 + 化整为零 并行与并发收 集器
简单垃圾回收器示意图

CMS使用的是标记清除算法,会带来内存碎片。

Stop The World

指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW

发表评论

您的电子邮箱地址不会被公开。