深入理解Java虚拟机:JVM高级特性与最佳实践(第三版)-笔记(3)-自动内存管理-垃圾收集器与内存分配策略
第二部分 自动内存管理-垃圾收集器与内存分配策略
一、导读
·第2章 Java内存区域与内存溢出异常
·第3章 垃圾收集器与内存分配策略
·第4章 虚拟机性能监控、 故障处理工具
·第5章 调优案例分析与实战
二、第3章 垃圾收集器与内存分配策略
3.1 哪些内存需要回收?
-
介绍:
第2章介绍了Java内存运行时区域的各个部分, 其中程序计数器、 虚拟机栈、 本地方法栈3个区
域随线程而生, 随线程而灭, 栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。
每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的( 尽管在运行期会由即时编译器进行一些优化, 但在基于概念模
型的讨论里, 大体上可以认为是编译期可知的) , 因此这几个区域的内存分配和回收都具备确定性,
在这几个区域内就不需要过多考虑如何回收的问题, 当方法结束或者线程结束时, 内存自然就跟随着
回收了。
而Java堆和方法区这两个区域则有着很显著的不确定性: 一个接口的多个实现类需要的内存可能
会不一样, 一个方法所执行的不同条件分支所需要的内存也可能不一样, 只有处于运行期间, 我们才
能知道程序究竟会创建哪些对象, 创建多少个对象, 这部分内存的分配和回收是动态的。 垃圾收集器
所关注的正是这部分内存该如何管理, 本文后续讨论中的“内存”分配与回收也仅仅特指这一部分内
存。
- 怎么判断哪些需要回收:
在堆里面存放着Java世界中几乎所有的对象实例, 垃圾收集器在对堆进行回收前, 第一件事情就
是要确定这些对象之中哪些还“存活”着, 哪些已经“死去”( “死去”即不可能再被任何途径使用的对
象) 了。
采用方法:
1)引用计数法
在对象中添加一个引用计数器, 每当有一个地方
引用它时, 计数器值就加一; 当引用失效时, 计数器值就减一; 任何时刻计数器为零的对象就是不可
能再被使用的。
注:但是JAVA虚拟机并没有使用引用计数法,其中的原因譬如单纯的引用计数就很难解决对象之间相互循环引用的问题。
2) 可达性分析算法
当前主流的商用程序语言( Java、 C#, 上溯至前面提到的古老的Lisp) 的内存管理子系统, 都是
通过可达性分析( Reachability Analysis) 算法来判定对象是否存活的。 这个算法的基本思路就是通过
一系列称为“GC Roots”的根对象作为起始节点集, 从这些节点开始, 根据引用关系向下搜索, 搜索过
程所走过的路径称为“引用链”( Reference Chain) , 如果某个对象到GC Roots间没有任何引用链相连,
或者用图论的话来说就是从GC Roots到这个对象不可达时, 则证明此对象是不可能再被使用的。
在Java技术体系里面, 固定可作为GC Roots的对象包括以下几种:
·在虚拟机栈( 栈帧中的本地变量表) 中引用的对象, 譬如各个线程被调用的方法堆栈中使用到的
参数、 局部变量、 临时变量等。
·在方法区中类静态属性引用的对象, 譬如Java类的引用类型静态变量。
·在方法区中常量引用的对象, 譬如字符串常量池( String Table) 里的引用。
·在本地方法栈中JNI( 即通常所说的Native方法) 引用的对象。
·Java虚拟机内部的引用, 如基本数据类型对应的Class对象, 一些常驻的异常对象( 比如
NullPointExcepiton、 OutOfMemoryError) 等, 还有系统类加载器。
·所有被同步锁( synchronized关键字) 持有的对象。
·反映Java虚拟机内部情况的JMXBean、 JVMTI中注册的回调、 本地代码缓存等。
- 引用介绍
在JDK 1.2版之后, Java对引用的概念进行了扩充, 将引用分为强引用( Strongly Re-ference) 、 软
引用( Soft Reference) 、 弱引用( Weak Reference) 和虚引用( Phantom Reference) 4种, 这4种引用强
度依次逐渐减弱。
强引用是最传统的“引用”的定义, 是指在程序代码之中普遍存在的引用赋值, 即类似“Object
obj=new Object()”这种引用关系。 无论任何情况下, 只要强引用关系还存在, 垃圾收集器就永远不会回
收掉被引用的对象。
软引用是用来描述一些还有用, 但非必须的对象。 只被软引用关联着的对象, 在系统将要发生内
存溢出异常前, 会把这些对象列进回收范围之中进行第二次回收, 如果这次回收还没有足够的内存,
才会抛出内存溢出异常。 在JDK 1.2版之后提供了SoftReference类来实现软引用。
弱引用也是用来描述那些非必须对象, 但是它的强度比软引用更弱一些, 被弱引用关联的对象只
能生存到下一次垃圾收集发生为止。 当垃圾收集器开始工作, 无论当前内存是否足够, 都会回收掉只
被弱引用关联的对象。 在JDK 1.2版之后提供了WeakReference类来实现弱引用。
虚引用也称为“幽灵引用”或者“幻影引用”, 它是最弱的一种引用关系。 一个对象是否有虚引用的
存在, 完全不会对其生存时间构成影响, 也无法通过虚引用来取得一个对象实例。 为一个对象设置虚
引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。 在JDK 1.2版之后提供
了PhantomReference类来实现虚引用。