大家好,今天和大家分享JAVA中的垃圾回收机制的简单执行过程。
《深入理解JAVA虚拟机》中说:JAVA和C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。可以简单理解一下:JVM的优势在于将程序员和内存分离,而JVM的劣势也在于程序员不能直接操作内存了。
其实说起垃圾收集机制(GC),很多人将这项技术当成了伴随着JAVA而产生的一项技术,但是事实上,在JAVA诞生之前,Lisp语言就已经开始使用内存动态分配和垃圾收集技术了。在GC还在襁褓中时,人们就开始考虑GC需要完成的事情:
1.怎么判断内存需要被回收。
2.被判定回收的内存在什么时候进行回收。
3.如何对内存进行回收。
我们今天来解释第一个问题:如何判断内存应该被回收。
首先可以这么理解,对于应该被回收内存,内存中保存的JAVA对象一定是已经“死亡“的对象,那么JVM是怎么判断对象死亡状态的呢?其中主要有以下两种方式:
1.引用计数法
在创建对象时,为对象创建一个伴生的引用计数器,当有其他对象引用该对象时,将引用计数器的值加1,如果其他对象不再引用该对象就将引用计数器的值减1,所以当引用计数器的值为0时,就代表不再有任何对象引用该对象,就说明该对象已经”死亡“,就可以被判定为待回收。
引用计数这种判定方法,实现比较简单,判定的效率也比较高,但是主流的虚拟机里面都没有选择这种方式,原因是什么呢?
这种方式其实存在一个难解的问题,就是对象之间的循环引用。如下:
我们看到对象a和对象b相互进行了引用,其余地方并没有对两个对象的引用了,但是两块内存的引用计数并不会为0,所以不会将两块内存划分为待回收的内存。由于以上原因,大部分的虚拟机并不会采用这种方式进行对象”死亡“状态判断的方法。
2.可达性分析算法:
在主流的JAVA,C#这类商用程序语言中,都是通过可达性分析算法判定对象是否存活的,基本思想是定义一个GC Root对象,以GC Root为起点,向下搜索,走过的路径称作引用链,当一个对象到GC Root之间没有任何的引用链可以连接时,表示这个对象可以被回收了。
在JAVA中,可以作为GC Root的对象包括以下几种:
1.虚拟机栈中引用的对象。
2.方法区中类静态属性引用的对象。
3.方法区中常量引用的对象。
4.本地方法栈中(Native方法)引用的对象。
在虚拟机通过可达性分析算法进行内存”死亡“状态判断时,就可以避免上面提到过的循环引用的问题了,所以主流的虚拟机都会采用这种方式来进行垃圾回收的第一个步骤。
好了,今天暂时先分享垃圾回收机制的第一个步骤,后续对之后的步骤进行详细的介绍。谢谢大家支持,如果觉得我的文章对您有用,请关注我们的公众号,每天一篇干货博文和实用面试题哦。