part2 自动内存管理机制
本章接着上一章的内容继续讲。本章的内容分两块:垃圾收集器和内存分配和回收策略,也就是内存的分配和回收。
章三 垃圾收集器和内存分配策略
首先谈内存分配。上一章节提到,JVM运行时内存分为5个区域,其中程序计数器,虚拟机栈和本地方法栈这三个区域是线程私有的,随线程创建而分配,线程死亡而收回,无需特别管理。而方法区和Java堆中的内存分配和回收则较为复杂,尤其是Java堆,是本章研究的重点。
下面谈垃圾收集器。顾名思义,垃圾收集器负责垃圾回收。那么,什么是垃圾,什么时候回收垃圾,怎样回收垃圾?这三个问题就是有关垃圾回收器设计的最核心问题。随后,还会讲述一些重要的垃圾回收器。
一 垃圾回收
1.1 什么是垃圾
前面说到,垃圾回收器是针对Java堆和方法区这两块内存区域进行回收,那么垃圾也就是这两块区域的垃圾。需要回收的垃圾主要分三种:Java堆中“已死”的对象实例,方法区中的废弃常量和无用的类。
下面的重点是:怎么判断一个对象实例“已死”,常量已被废弃,类无用了?
考虑到判断对象实例的生死是这里的重点,也是垃圾回收器回收最频繁高效的区域,且废弃常量的判定与其基本一致。这里先讲对无用的类的判定。对类无用的判定比较复杂,需要同时满足下面三个条件:
- 该类的所有实例已经被回收(Java堆中不存在该类实例)
- 加载该类的ClassLoader已经被回收
- 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过放射访问该类的方法
对于满足上述3个条件的无用类,JVM可以进行回收,根据设置而定。需要注意的是,对于大量使用反射、动态代理和CGLib等ByteCode框架、动态生成JSP及OSCi这类频繁自定义ClassLoader的场景需要设置类卸装功能,防止方法区(HotSpot中的永生代)溢出。一般情况下,不用担心溢出问题。
下面谈这里的重点,Java堆中的对象生死判定。这里涉及到两个算法:引用计数算法和可达性分析算法。