一、按代实现垃圾回收
先看一下整体结构:
新生代(Young generation):
绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为”minor GC“。
新生代中存在一个Eden区和两个Survivor区。新对象会首先分配在 Eden 中(如果新对象过大,会直接分配在老年代中)。在GC中,Eden 中的对象会被移动到survivor中,直至对象满足一定的年纪(定义为熬过GC的次数),会被移动到老年代(具体细节将在下边垃圾收集算法中讨论)。可以设置新生代和老年代的相对大小。这种方式的优点是新生代大小会随着整个堆大小动态扩展。参数 -XX:NewRatio 设置老年代与新生代的比例。例如 -XX:NewRatio=8 指定老年代/新生代为8/1. 老年代占堆大小的 7/8 ,新生代占 1/8 .(默认即使1/8)
年老代:
内存里包含了长期存活的对象和经过多次Minor GC后依然存活下来的对象。通常会在老年代内存被占满时进行垃圾回收。老年代的垃圾收集叫做Major GC。Major GC会花费更多的时间。
持久代:
Java对象是java 类的实例。每当创建一个Java对象时,Java虚拟机都会创建该对象的内部引用并且保存在堆中。如果一个类是第一次访问,那么它必须通过Java虚拟机加载进来。类加载是定位,寻找,加载class文件和解析class文件结构的过程。类加载器负责确保加载正确的class文件。Java程序里面每一个class文件需要被同一个类加载加载。类加载器是 java.lang.ClassLoader 类的实例。目前为止,类加载器是在持久代空间里面加载类的。
Java虚拟机也创建了Java类的内部引用保存在持久代。在垃圾回收期间,Java对象和类都当做对象处理并且以同样的方式回收。最初Java对象和类都是保存在堆中。
一个性能优化措施:一旦持久代创建后,就会把classes放入里面。Classes是Java虚拟机的部分实现,我们不应该用我们的数据结构填满Java堆。持久代包含以下类信息:
- 类方法
- 类名称
- 常量池信息
- 对象数组和与类相关的类型数组
- 被Java虚拟机使用的内部对象
- 编译器用于优化的信息
持久代空间
当Java虚拟机需要加载定义的一个新class,但是在持久代中没有足够的空间就会抛出‘Java.Lang.OutOfMemoryError: PermGen Space’异常。默认分配给持久代的大小在server模式下是64MB ,在client模式下是32MB 。这就有两个原因可能会引起持久代内存溢出问题的发生。
第一个原因可能是你应用或者服务器已经有非常多的class在你的持久代中,已经不能容纳所有的class了。
引用计数收集算法
用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象(不是引用)都有一个引用计数。当一个对象被创建时,且将该对象分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集时,它引用的任何对象计数减1。
优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。
缺点: 无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.
可达性分析算法
通过一系列称为”GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所有走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(从GC Roots到此对象不可达),则证明此对象是不可用的。
可作为GC Roots的对象包括:
- 虚拟机栈中所引用的对象(本地变量表)
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象(Native对象)
- 强引用(Strong Reference): 在代码中普遍存在的,类似”Object obj = new Object()”这类引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象
- 软引用(Sofe Reference): 有用但并非必须的对象,可用SoftReference类来实现软引用,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行二次回收。如果这次回收还没有足够的内存,才会抛出内存异常异常。
- 弱引用(Weak Reference): 被弱引用关联的对象只能生存到下一次垃圾收集发生之前,JDK提供了WeakReference类来实现弱引用。
- 虚引用(Phantom Reference):也称为幽灵引用或幻影引用,是最弱的一种引用关系,JDK提供了PhantomReference类来实现虚引用。