JVM专题-垃圾回收
Posted IT-老牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM专题-垃圾回收相关的知识,希望对你有一定的参考价值。
文章目录
1.垃圾回收算法
1.1.标记清除
将没有被引用的对象标记出来,然后清除。这里的清除并不是把内存空间置零操作,而是把这些空间记录下来,待后面分配空间的时候,去寻找是否有空闲的空间,然后进行覆盖分配。
优点:速度较快
缺陷:清除的空间比较零碎,当待分配的新对象过大,即使零碎空间加起来总共是够的,但是由于过于零散,所以无法对其进行分配。
1.2.标记整理
优点:没有内存碎片,连续空间比较充足
缺点:涉及到地址的改变,开销大,效率低
1.3.复制
优点:不会有内存碎片
缺陷:始终会占用双倍的内存空间
2.分代垃圾回收
- Jvm将堆分为了新生代和老年代。
- 对新生代的垃圾回收更加频繁,对老年代的垃圾回收频率低一些
- 新生代主要存放临时的、迭代快的对象,老年代存放仍然经常使用的对象
- 新生代类似每天打扫,老年代类似大扫除
- 对象首先分配在伊甸园区域。
- 新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换from 和 to 所指向的空间,即始终让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专题-垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章