文章目录
0. 如何判断Java中对象是否存活?
0.1 引用计数算法
引用计数算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器+1,当引用失效的时候,计数器-1,当计数器为0的时候,JVM就认为该对象不再被使用,是“垃圾”了。
引用计数实现简单,效率高;但是不能解决循环引用问问题(A对象引用B对象,B对象又引用A对象,但是A,B对象已不被任何其他对象引用),同时每次计数器的增加和减少都带来了很多额外的开销,所以在JDK1.1之后,这个算法已经不再使用了。
0.2 根搜索方法
根搜索方法是通过一些GCRoots
对象作为起点,从这些节点开始往下搜索,搜索通过的路径成为引用链(ReferenceChain),当一个对象没有被GCRoots
的引用链连接的时候,说明这个对象是不可用的。
GCRoots对象包括:
- 虚拟机栈(栈帧中的本地变量表)中的引用的对象。
- 方法区域中的类静态属性引用的对象。
- 方法区域中常量引用的对象。
- 方法栈中JNI(
Native
方法)的引用的对象。
1. 复制算法(Copying):适用于新生代
1.1 原理分析
虚拟机把新生代分为了三部分:1个Eden
区和2个Survivor
区(分别叫from
和to
),默认比例为8:1:1。
一般情况下,新创建的对象都会被分配到Eden
区(一些大对象特殊处理),这些对象经过第一次Minor GC
后,如果仍然存活,将会被移到Survivor
区。对象在Survivor
区中每熬过一次Minor GC
,年龄 +1,当它的年龄增加到一定程度时(默认是 15 ,通过-XX:MaxTenuringThreshold
来设定参数),就会被移动到年老代中。
因为新生代中的对象基本都是朝生夕死(被GC回收率90%以上),所以在新生代的垃圾回收算法使用的是复制算法。
复制算法的基本思想就是将内存分为两块,每次只用其中一块(from
),当这一块内存用完,就将还活着的对象复制到另外一块上面。
我们来举个栗子,在GC开始的时候,对象只会