java垃圾回收器

概述:在java中我们不需要管理垃圾回收,但是如果我们觉得这种回收的效率比较低不能达到我们的目的时,我们就要自己去了解。

程序计数器,虚拟机栈,本地方法栈都是线程私有的,随着线程的存在而生,随线程而灭,栈中的栈帧随着方法的进入和退出而有条不紊的执行着出栈和入栈操作,每一个栈帧中药分配多少内存基本已经确定下了了,所以这几个区域的内存分配和回收都具备确定性。

但是java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行时期才能知道创建那些对象,这部分的内存的分配和回收都是动态的。

在进行垃圾回收之前,垃圾收集器首先确定的是这些对象那些还活着,那些已经死去,主要有两种方法,引用计数法和可达性分析算法。

引用计数法:给对象添加一个引用计数器,每当有一个对象引用它时,计数器值就加1,当引用失效时,计数器值就减一,任何时刻的计数器为0的对象就是不可能再被使用的,但是这个算法很难解决对象之间相互循环引用的问题,如果两个对象相互引用着对方,导致他们的引用计数都不为0,于是引用计数都不为0,于是引用计数法无法通知GC收集器回收他们。

可达性分析法:通过一系列的称为GC Roots 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连时(也就是不可达),则证明这个对象是不可用的。

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

虚拟机栈中引用的对象/方法区类静态属性引用的对象/方法区常量引用的对象/本地方法栈引用的对象。

引用:这两种判断方法都离不开引用,在JDK1.2之前时,引用的定义很传统:如果reference类型数据中存储的数据代表的是梁歪一块内存的起始地址,就称这个这块内存代表着一个引用。但是这种引用的定义有一定的局限性,因为我们有可能想要一些对象在内存空闲的情况下保存下来,在内存紧张的时候,将他们清除掉,比如很多系统的缓存功能,在jdk1.2之后,将引用分为强引用,弱引用,软引用,虚引用

强引用:在程序中普遍存在的,如Object a = new Object ();只要强引用还在,垃圾回收器永远不会回收掉被引用的对象。

软引用:存在但非必须的,在快要内存溢出时将其清除掉。

弱引用:强度比软引用更弱一些,被软引用引用的对象,只能生存到下一次垃圾回收发生之前。

虚引用:存在唯一目的是在这个对象被垃圾回收器回收之前可以收到一个系统通知。


即使在可达性分析算法不可达的对象也并不是非死不可的,至少要经过两次标记过程。如果对象在可达性分析算法不可达之后,那么将会被第一次标记然后进行筛选,筛选的条件是这个对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这种情况都视为“没有必要执行”。finalize()方法是在等待队列中逃脱死亡的最后一次机会,GC会对队列中的对象进项第二次标记,如果对象要在finalize()成功拯救自己,只需要与可达链上面的任何一个对象简历联系就可以了,第二次标记就会移除出需要移除的队列。


永久代也就是方法区的垃圾回收效率比较低,主要回收两类数据:废弃常量,无用的类。

废弃常量的判断和无用对象的判断是一样的,无用的类判断比较麻烦,需要满足以下三项条件。

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

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

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

满足上面是哪个条件就可以被回收了。




猜你喜欢

转载自blog.csdn.net/lsm18829224913/article/details/80246573