JVM专题-垃圾回收

Posted IT-老牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM专题-垃圾回收相关的知识,希望对你有一定的参考价值。

文章目录

1.垃圾回收算法

1.1.标记清除


将没有被引用的对象标记出来,然后清除。这里的清除并不是把内存空间置零操作,而是把这些空间记录下来,待后面分配空间的时候,去寻找是否有空闲的空间,然后进行覆盖分配。

优点:速度较快

缺陷:清除的空间比较零碎,当待分配的新对象过大,即使零碎空间加起来总共是够的,但是由于过于零散,所以无法对其进行分配。

1.2.标记整理


优点:没有内存碎片,连续空间比较充足
缺点:涉及到地址的改变,开销大,效率低

1.3.复制


优点:不会有内存碎片
缺陷:始终会占用双倍的内存空间

2.分代垃圾回收

  • Jvm将堆分为了新生代老年代
  • 对新生代的垃圾回收更加频繁,对老年代的垃圾回收频率低一些
  • 新生代主要存放临时的、迭代快的对象,老年代存放仍然经常使用的对象
  • 新生代类似每天打扫,老年代类似大扫除

  • 对象首先分配在伊甸园区域。
  • 新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换fromto 所指向的空间,即始终让to空间保持空闲。
  • minor gc 会引发stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才恢复运行。
  • 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)。
  • 当老年代空间不足,会先尝试触发minor gc,如果之后空间仍不足,那么触发full gc,STW的时间更长
  • 如果仍然不足,会抛出OutOfMemory异常。

3.相关VM参数

含义参数
堆初始大小-Xms
堆最大大小-Xmx 或 -XX:MaxHeapSize=size
新生代大小-Xmn或(-XX:NewSize=size±XX:MaxNewSize=size)
幸存区比例(动态)–XX:InitialSurvivorRatio=ratio和-XX:+UseAdaptiveSizePolicy
幸存区比例-XX:SurvivorRatio=ratio
晋升阈值-XX:MaxTenuringThreshold=threshold
晋升详情-XX:+PrintTenuringDistribution
GC详情-XX:+PrintGCDetails -verbose:gc
FullGC前MinorGC-XX:+ScavengeBeforeFullGC

3.1.实例

# 虚拟机参数
-Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC
/**
 * -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC
 *  演示内存的分配策略
 */
public class Demo2_1 
    private static final int _512KB = 512 * 1024;
    private static final int _1MB = 1024 * 1024;
    private static final int _6MB = 6 * 1024 * 1024;
    private static final int _7MB = 7 * 1024 * 1024;
    private static final int _8MB = 8 * 1024 * 1024;

    // -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC
    public static void main(String[] args) throws InterruptedException 

    


当分配空间后

public static void main(String[] args) throws InterruptedException 
    ArrayList<byte[]> list = new ArrayList<>();
    list.add(new byte[_7MB]);



再次分配

public static void main(String[] args) throws InterruptedException 
    ArrayList<byte[]> list = new ArrayList<>();
    list.add(new byte[_7MB]);
    list.add(new byte[_512KB]);
    list.add(new byte[_512KB]);


大对象直接晋升到老年代

public static void main(String[] args) throws InterruptedException 
    ArrayList<byte[]> list = new ArrayList<>();
    list.add(new byte[_8MB]);



当对象过大,新生代放不下后,不会触发GC,会直接放到老年代。当老年代也不足时,会OOM异常。

进程内的OOM不会影响到主线程的运行

public static void main(String[] args) throws InterruptedException 
    new Thread(() -> 
        ArrayList<byte[]> list = new ArrayList<>();
        list.add(new byte[_8MB]);
        list.add(new byte[_8MB]);
    ).start();

    System.out.println("sleep....");
    Thread.sleep(1000L);


以上是关于JVM专题-垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章

java垃圾回收机制

JVM 专题二十一:垃圾回收垃圾回收器

JVM学习--垃圾回收器

JVM专题-垃圾回收

JVM专题-垃圾回收

JVM专题-垃圾回收