《深入理解JAVA虚拟机》第三章

垃圾收集机制(简称GC),比Java诞生的早,GC要完成的三件事:

  • 那些内存需要回收
  • 什么时候回收
  • 怎么回收

判断一个对象是否存活简单的方法:在对象中加入一个引用计数器,当一个地方引用它时,计数器值加一,当引用失效时,计数器值减一。当计数器值为零时,对象就不可用了。

但是主流的JVM中都没用这个方法,因为存在许多例外情况,导致处理这些情况需要大量额外处理才可以保证正确工作。

可达性分析算法

主流的JVM是使用的时可达性分析算法来判定对象是否存活。判定条件是由GC Roots节点开始,向下搜索,如果GC Roots到对象是不可达的,那么此对象就是不被使用的。

 5、6、7就不可达,所以他们就是需要回收的。

 当然用户可以自定义一些GC Roots。

引用

JDK1.2后,引用可分为强引用、软引用、弱引用、虚引用四种。强度依次递减。

强引用是指代码中普遍存在的引用赋值,只要强引用关系在,就永远不会被回收。

软引用是描述一些还有用但非必须的对象,只被软引用关联的对象,会在内存溢出异常前,被二次回收,回收后内存还是不够,才会报异常。

弱引用也是描述非必要的的对象。但比软引用还弱,被关联的对象只能活在下一次回收为止,也就是当GC工作开始,不管内存是否足够,对象都会别回收。

虚引用是最弱的一种,也被称为“幽灵引用”,对象是否存在虚引用对于其的生存时间没用任何影响,当然也无法通过它调用一个对象,加设它的原因是为了给对象被回收时增加一个系统通知。

“宣告死亡”

对象真正死亡是不容易的,至少需要经过两次标记:如果可达性分析发现它与GC Roots没有引用链了,会被标记一次,随后进行一次筛选,检查是否有必要finalize()方法,如果对象没有覆盖finalize()方法或者以经被调用过了,那么就没必要执行,反之有必要。这时对象会被放在一个F-Queue队列中,会有一个由虚拟机创建的Finalizer线程去执行finalize()方法,这个执行并意味着虚拟机会等待方法运行结束。防止finalize()方法运行过慢导致回收系统崩溃。稍后GC就会对对象进行第二次标记,如果这个对象在finalize()运行时与任何一个引用链上的对象建立联系,都会将它移出“即将回收”的集合,如果没有那就会被回收。

方法区的回收

《JVM规范》中提到,方法区可以不设垃圾收集。因为方法区垃圾收集性价比比较低,方法区的回收有非常苛刻的判定条件,而且回收成果远低于其他常规的垃圾收集释放的内存空间。

方法去的垃圾收集主要会后两部分:废弃的常量和不再使用的类型。回收常量就是没有其他的地方引用这个常量就需要回收。回收“不再使用的类型”就比较苛刻了,

 三个条件需要同时满足才可以回收,这里的回收也只是可以回收。确定回收还存在另外的控制。

垃圾收集算法

算法可以分为“引用计数式收集”和“追踪式垃圾回收集”。也可以叫做“直接垃圾收集”和“间接垃圾收集”。

分代

分代理论有三条假说:

  1. 弱分代假说:绝大多数对象时朝生夕灭的
  2. 强分代假说:熬过越多次收集的对象就越难以消亡
  3. 跨代引用假说:跨代引用相对于同代引用来说就占少数

一般Java堆划分为新生代、老年代两个区域。随着收集次数的增加,对象会逐步晋升到老年代。

这里会存在一种老年代引用新生代的情况,随着收集次数,老年代的难以消亡,新生代也就变为老年代了跨代引用就消失了。如果没有假说三,就需要专门记录对象是否存在以及存放着那些跨代引用。这里只需要建立一个全局的数据结构记录,老年代中哪一块内存有跨代引用,当发生新生代收集时,只有存在跨代引用的内存块才会被加入GC Roots进行扫描。

标记-清除算法

最早的最基础的垃圾收集算法。标记所有需要回收的对象,标记完成后,统一回收所有标记的对象;也可以反过来,标记不需要回收的,统一回收未标记的。

 标记-复制算法

为解决标记-清楚算法的处理大量需要回收的对象效率低的问题,提出了这个标记-复制法,将内存分为两块,先只使用一块,等这块用完的时候,将存活的对象复制到另一块,在将这块一次性清除,当需要回收占大多数的时候,只需将少部分存活的复制过去了,实现简单,但是,可用内存缩小了一半,空间浪费加大。

 现在主流的JVM优先使用这种方法进行回收新生代。曾经IBM研究新生代中98%的对象都是需要回收的,所以这种方法处理新生代优先级比较高。

后面有的虚拟机为了更好的利用内存,将内存分为一块大两块小的,每次只使用那块大的和其中一块的,回收的时候将存活的对象复制到另一块小的上,然后清掉两块用过的。HotSpot虚拟机按照上面的方法,将内存分为8:1:1也就是每次新生代可用的内存为整个90%,将浪费的空间缩小到10%,当然为了避免意外,所划分的内存块是可以扩容的,回从其他区域进行调用。

标记-整理算法

老年代是不使用标记-复制法的,于是有了标记-整理法,标记与标记-清除无异,只是后面不直接将可回收的对象进行清理,将所有存活的对象向一端移动,直接清楚调边界以外的内存。

 这几种算法都有利弊,很多虚拟机都是按照需求进行不同的分配使用。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值