在对象中加入一个计数,表示这个对象被引用的数量,每当一个新的引用指向对象,引用计数+1,一个引用不再指向对象,引用计数-1;当这个引用计数为0的时候,没有引用指向这个对象了,这个对象就是垃圾

像这样,如果两个对象互相引用,他们的引用计数都为1,但是这两个对象都不会被使用到,这两个对象实际上都是垃圾,但无法被检测出来
扫描堆中的所有对象,判断每个对象是否能沿着GC Root对象的引用链找到该对象;如果能找到,说明该对象不是垃圾,如果找不到,说明这个对象是垃圾
GC Root对象的组成
不难发现GC Root都是现在正在使用和将来可能会使用的对象,如JVM栈和本地方法栈中引用的对象,正在执行的方法将会使用到这些对象,所以这些对象引用链上的对象都不能释放;方法区中的对象都是和类相关的全局变量,不该被释放
虚拟机参数:-Xmx10M将堆内存最大值设置为10M
public class Main{
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<SoftReference<byte[]>> list = new ArrayList<>();
// 创建引用队列
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for(int i=0;i<5;i++){
// 将引用队列与软引用进行关联,当软引用引用的对象由于内存不足被回收,软引用会进入引用队列
list.add(new SoftReference<>(new byte[_4MB],queue));
}
System.out.println(list.size());
// 将软引用引用的对象进行回收
Reference<? extends byte[]> poll = queue.poll();
while(poll!=null){
list.remove(poll);
poll = queue.poll();
}
System.out.println(list.size());
}
}


将内存空间划分为from和to两个区域,从from标记所有存活的对象,复制到to中,from中内存全部释放;然后交换from和to的位置

优点
速度快,且不会有内存碎片
缺点
需要消耗双倍的内存空间
新创建的对象都会创建到新生代的Eden区
当Eden内存空间不足时,就会触发Minor GC,将Eden中存活的对象复制到Survivor_To区域,并将存活对象的寿命+1,然后交换Survivor_From和Survivor_To的位置;接下来再次遇到Eden内存不足除了将Eden区域的存活对象复制到Survivor_To中还会将Survivor_From区的存活对象复制到To中
如果某个对象达到了年龄阈值(默认15,也是最大阈值,因为对象头中该数据大小为4bit),或者Survivor_To区域的空间不足时,新生代中的对象将会向老年代中晋升(如果出现大对象也会直接进入老年代,通过-XXPretenureSizeThreshold设置直接进入老年代的大对象大小)
当老年代空间不足,会先触发Minor GC,触发之后如果空间仍然不足,会触发Full GC;此时将老年代中的空间进行回收,然后将新生代中的对象晋升
垃圾回收过程会触发stop the world,即暂停其他用户线程,因为垃圾回收会改变对象的地址,如果线程仍然在运行会找不到使用的对象,等待垃圾回收结束才恢复;minor GC的耗时短、full GC的耗时长
| 参数 | 含义 |
|---|---|
| -XMs | 堆初始大小 |
| -Xmx或-XX:MaxHeapSize=size | 堆最大大小 |
| -Xmn | 同时配置新生代初始大小和最大大小 |
| -XX:NewSize=size | 新生代初始大小 |
| -XX:MaxNewSize=size | 新生代最大大小 |
| -XX:InitialSurvivorRatio=ratio | 幸存区初始比例 |
| -XX:+UseSerialGC | 使用串行垃圾回收器 |
| -XX:+UseAdapriveSizePolicy | 打开动态调整幸存区比例开关 |
| -XX:SurvivorRatio=ratio | 固定幸存区比例 |
| -XX:MaxTenuringThreshold | 晋升阈值 |
| -XX:+PrintTenuringDistribution | 打印晋升详情 |
| -XX:+PringGCDetails -verbose:gc | 打印GC详情 |
| -XX:+ScavengeBeforeFullGC | 在FullGC前进行MinorGC |
使用VM参数:-Xms20M -Xmx20M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc |
初始状态

public class Main{
private static final int _512KB = 512 * 1024;
private static final int _1MB = 1024 * 1024;
private static final int _4MB = 4 * 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 -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc
* @param args
*/
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
// 添加4M的数据到eden区
list.add(new byte[_4MB]);
}
}
触发Minor GC

public class Main{
private static final int _8MB = 8 * 1024 * 1024;
/**
* -Xms20M -Xmx20M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc
* @param args
*/
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
// 添加4M的数据到eden区
list.add(new byte[_8MB]);
list.add(new byte[_8MB]);
}
}



