JVM GC内存回收
有很多类似的名词,GC,垃圾回收,空间整理,内存回收。这些词基本都可以大概的描述我们接下来的内容。
有几个问题,要先提出,
- 为什么要回收内存?
- 哪些内存要回收?
- 什么时候回收?
- 怎么干?
第一个很明显,因为空间不是无限的,当JVM可利用的内存空间越来越小,就会导致无法给新的对象分配内存,导致OOM
第二个问题,哪些内存要回收,我们不能把正在使用的内存给回收了,那样会导致系统的异常。所以如果知道哪些内存需要回收,需要一些方法来确定。
比较通俗的说法就是已经“死”掉的对象,可以理解成是系统不再用了。
这就出现了新问题,如何判断对象是否成活?
引用计数法(Reference Counting)
一种是 引用计数法(Reference Counting),概念是在对象中添加一个引用计数器,有引用的它的时候,计数器+1,引用失效,计数器-1;计数器为0就代表对象不可再被使用。
看上去很简单,但是有很多问题情况要考虑,一个比较大的问题就是很难解决对象之间相互循环引用的问题,不是说无法解决,而是很难。
可达性分析方法(Reachability Analysis)
另一种是 可达性分析方法(Reachability Analysis),思路是通过一系列‘GC Roots’的根对象作为开始节点集,从节点开始根据引用关系向下搜索,搜索过程的路径称为‘引用链’(reference chain),如果对象到 roots没有任何引用链,就说明对象不可能被使用
GC Roots的对象包含:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象,例如各个线程被调用的方法堆栈中使用的参数,局部变量,临时变量等。
- 方法区中类静态属性引用的对象,例如JAVA类的引用类型静态变量
- 方法区中常量引用的对象,例如字符串常量池里的引用。
- 本地方法栈中JNI(Native方法)引用的对象。
- Java虚拟机内部的引用。
- 所有被同步锁(synchronized)持有的对象
- 反映Java虚拟机内部情况的JMXBean,JVMTI中注册的回调,本地代码缓存等。
第3个问题,什么时候回收,一般是GC收集器自己来决定的,因为实现GC功能的收集器很多,具体要看他们自己是什么时候执行。Coder即使触发GC,GC也不会立即执行。
第4个问题,怎么干?
从这里开始就会涉及到GC的一些算法理论,后面再说。简单来说,在GC之后,JVM就会有空闲可用的内存空间,如果还是没有足够的内存空间,那就会OOM。