垃圾收集器和内存分配策略

2020-02-05  本文已影响0人  官子寒

1. 概述

2. 对象已死?

如何判断对象是否已经死去?主要使用的方法包括引用计数法根搜索算法

2.1 引用计数法

给对象添加一个引用计数器,每当有一个地方引用它时,就加1;当为0时就认为这个对象不再使用

优点:简单高效
缺点:不能解决循环引用的问题

public class ReferenceCountingGC {
    public Object isntance;

    private final int _1MB = 1024 * 1024;

    private byte[] arr = new byte[10 * _1MB];

    public static void main(String[] args) {
        ReferenceCountingGC a = new ReferenceCountingGC();
        ReferenceCountingGC b = new ReferenceCountingGC();

        a.isntance = b;
        b.isntance =a;//如果是引用计数法,在这儿会加1

        a  = null;
        b = null;


        System.gc();//那么在这儿不会清除a和b
    }
}
GC日志

可以看出Java中不是 使用引用计数法来判断

2.2 根搜索算法

通过一系列GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则认为它不可用了

在Java语言里,可作为GC Roots对象的包括如下几种:
a.虚拟机栈(栈桢中的本地变量表)中的引用的对象
b.方法区中的类静态属性引用的对象
c.方法区中的常量引用的对象
d.本地方法栈中JNI的引用的对象

2.3 再谈引用

Java中将引用分成强引用软引用弱引用虚引用

2.4 生存还是死亡

根搜索算法
public class SaveHook {
    public static SaveHook saveHook = null;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize Executed");
        SaveHook.saveHook = this;
    }

    private void isAlive() {
        System.out.println("I am alive");
    }

    public static void main(String[] args) throws InterruptedException {
        saveHook = new SaveHook();
        saveHook= null;

        System.gc();

        Thread.sleep(500); //如果没有等待,则会因为没有救赎而直接死亡

        if(saveHook != null){
            saveHook.isAlive();
        } else {
            System.out.println("dead");
        }

    }
}

2.5 回收方法区

永久代的垃圾回收分为两部分:废弃常量无用的类
1)废弃常量判定方法:是否有引用
2)无用的类判定方法:需要满足3个条件

1.该类所有的实例都被回收,也就是Java堆中不存在该类的任何实例
2.加载该类的ClassLoader已经被回收
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

3. 垃圾收集算法

3.1 标记-清除算法

缺点:
1)效率问题:标记和清除的效率都太低
2)空间问题:容易产生空间碎片,当程序在接下来运行中需要分配大量连续内存空间时,会再次触发垃圾收集算法

标记-清除算法

3.2 复制算法

3.3 标记-整理算法

标记-整理算法

3.4 分代收集算法

4. 垃圾收集器

收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现

4.1 Serial收集器

优点:
1.简单高效,专心单线程收集,没有线程交互开销
2.适用于Client模式下的虚拟机

4.2 ParNew收集器

4.3 Parallel Scavenge收集器

停顿时间越短,越适合与用户交互的程序
吞吐量高则适合在后台计算,交互少的程序

4.4 Serial Old收集器

4.5 Parallel Old收集器

4.6 CMS收集器

浮动垃圾:垃圾收集阶段程序还需要运行而产生的垃圾

  1. 标记-清除算法可能会导致大量空间碎片

4.7 G1收集器

与CMS收集器相比的改进:

  1. 采用标记-整理算法,不会产生时间碎片
  2. 可以非常精确地控制停顿,达到实时Java

4.8 参数总结

JVM - 垃圾收集器参数总结

5. 内存分配和回收策略

5.1 对象优先在Eden分配

public class TestAloocation {
    private final static int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[4 * _1MB];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        allocation4 = new byte[2 * _1MB];


    }
}
优先给Eden分配

5.2 大对象直接进入老年代

5.3 长期存活对象进入老年代

5.4 动态对象年龄判定

5.5 空间分配担保

在发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的平均大小是否大于剩余空间大小,如果大于,则改为直接进行一次Full GC;如果小于,则查看HandlerPromotionFailure是否开启,如果开启则进行Minor GC;没有开启,则会进行Full GC

上一篇 下一篇

猜你喜欢

热点阅读