JVM GC概述
垃圾回收器,简称GC,也可以说是内存回收器,垃圾回收是JVM中最核心的功能之一。垃圾回收器主要关注三个问题:
- 哪些内存需要回收(JVM运行时数据区内哪些区域需要进行内存回收)
- 什么时候回收
- 如何回收(用什么方法回收)
Java开发者无须像C/C++开发者那样关注于内存相关的细节(内存申请、回收等),是得益于JVM的内存自动回收技术。而了解JVM的内存回收有益于,排查内存泄漏、内存溢出等问题,以及当垃圾回收成为高并发的瓶颈时对垃圾回收的实施必要的调节。虽然上述几种问题在生产环境很难遇到,但是多了解垃圾回收相关技术也是有必要的。
哪些内存需要回收
Java内存运行时区域包括,程序计数器、虚拟机栈、本地方法栈、堆、方法区。
其中程序计数器、虚拟机栈、本地方法栈区域中数据随着线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性(当方法结束或线程结束后就可以回收内存)。
Java堆和方法区的内存需要GC回收,因为这两个区域的内存不具备确定性,一个接口的多个实现类需要的内存可能会不一样,一个方法所执行的不同条件分支所需要的内存也可能不一样,只有处于运行期间,我们才能知道程序究竟会创建哪些对象,创建多少个对象,这部分内存的分配和回收是动态的。
什么时候回收
Java堆中存放的所有对象实例,GC进行内存回收的首要条件是判断哪些对象实例可以回收,可以认为对象被判定为“死亡”后,就会被回收调内存。
怎么判定一个Java对象实例“死亡”?
一般有两种方式:
- 引用计数算法(存在明显的缺陷,主流的JVM没有采用此方法管理内存)
- 可达性分析算法
可达性分析算法
通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GCRoots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。
哪些对象可以作为GC Roots对象?
即使在可达性分析算法中判定为不可达的对象,也不是“非死不可”的,这时候它们暂时还处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程。可以通过重载实现finalize方法实现逃逸,即下图中最下面的是否重新引用的判断块中,重新被引用,但每个实例对象的finalize方法只会最多被系统调用执行一次。
如何回收
后续继续完善
参考
全文参考来自书籍<深入理解Java虚拟机:JVM高级特性与最佳实践>第三章