您的位置:首页 > 编程语言 > Java开发

Java虚拟机知识整理——垃圾的判断

2016-07-18 06:20 309 查看
说起垃圾收集(GarbageCollection,GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史比Java久远,1960年诞生与MIT的Lisp是第一门真正使用动态分配和垃圾收集技术的语言。

经过半个多世纪的发展,目前内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了“自动化”时代,为什么还需要了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出、内存泄露问题时,当垃圾手机成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。

对象死了吗?

垃圾收集器在对堆进行回收前,需要判断对象那些还“存活”着,哪些已经“死去”。然后才能对“死去”的对象进行回收。

引用技术算法

引用计数算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被引用的。

引用计数算法的实现简单,判定效率也很高,在大部分情况喜爱它都是一个不错的算法,但是至少主流的Java虚拟机里面没有选用医用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。

可达性分析算法

在主流的商用程序语言的主流实现专攻,都是称通过可达性分析来判定对象是否存活的。这个算法的基本思想是通过一系列的成为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索锁走过的路径称为引用链,当一个对象到GC Roots没有任何因用力按相连接时则证明此对象是不可用的。

在java语言中,可作为GC Roots的对象包括下面几种:

1.虚拟机栈(栈帧中的本地变量表)中引用的对象。

2.方法去中金泰属性引用的对象。

3.方法区中常量引用的对象。

4.本地方法栈中JNI(即一般说的Native方法)引用的对象。

我还想再抢救一下

及时在可达性分心算法中的不可达对象,也并非是“Facebook(非死不可)”的,这时候他们暂时处于“缓刑”阶段,如果还想‘再抢救一下’还可以用finalize()标记。因为真正宣告一个对象死亡,至少要经历两次标记过程:第一次标记有没有与GC Roots想链接的引用链,那它将会被第一次标记并开始第一次筛选,帅选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()已经被虚拟机调用过,虚拟机将这两种情况都视为“没必要执行”。但是finalize()方法调用不一定会成功,如果不成功,那么对象也只能“死去”。

所以,简单来说finalize()可以让要“死去”的对象“再抢救一下”,如果“抢救”成功,就可以多存活一会,如果“抢救”失败也只能死亡。

回收方法区

方法区的垃圾手机主要回收两部分内容:废弃常量和无用的类。

要判断一个常量是否是“废弃变量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。需要满足一下三个条件:

1.该类所有的实例都已经被回收也就是Java堆中不存在该类的任何实例。

2.加载该类的ClassLoader已经被回收。

3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

满足上面的三个条件,仅仅是可以回收,会不会回收还要取决于虚拟机的其他判断是否通过。因为类是否无用相对来说需要更多的条件。

所以就是垃圾了

对象被判断为垃圾,没有进行成功的“抢救”,就说明对象可以被回收了。当垃圾回收的线程开始运行的时候就会开始回收这些垃圾。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息