JAVA垃圾回收机制2

一、分代收集理论

主流垃圾回收器都遵循两个理论:

  1. 弱分代理论:绝大多数对象都有会很快死亡。
  2. 强分代理论:经过越多次回收的对象生命周期越长,越难以消亡。

由这两个理论我们可以自己去“设计”回收机制:既然绝大多数对象都会很快死亡,那么应该更多地关注不会很快死亡的对象,这样可以反向筛选出来需要回收的对象。同时,我们可以把经历了不同回收次数的对象放在不同区域里,来反映其生命周期的长度。

显然当时的设计者就是这样想的,JAVA堆中所谓新生代、老年代就是出于这种考虑设计出来的。

  • 新生代:主要存放刚建立的对象
  • 老年代:存放经历多次垃圾收集后仍然存活的对象,suvivor里不够放下的对象,G1的大对象

显然,我们只需要经常回收新生代的对象,再把经历多次回收的对象搬迁到老年代,这样每次回收的内存碎片会很少,性能会提升很大,那么这样有什么问题呢?

假如老年代引用了新生代的对象,那我们肯定不愿意“不小心”把这个新生代对象给回收掉导致空指针问题,这种现象就叫“跨代引用”。如何解决这个问题呢?

大量数据证明,跨代引用其实是很少见的,而且跨代引用的对象经过多轮回收也会假如老年代,届时跨代引用就不存在了,所以我们不应该为了跨代引用而去每次扫描所有老年代对象,而是在新生代上加一个全局数据结构--记忆集,来记录老年代的哪一块内存有跨代引用,这样每次只需要扫描记忆集,然后把新生代其他对象回收掉就行了。

另外这里顺便记录几个名词:

回收方式共有4种:

  1. 新生代收集(Minor GC/Young GC): 只针对新生代的回收
  2. 老年代收集(Major GC/Old GC): 只针对老年代的收集(目前只有CMS收集器有)
  3. 混合收集(Mixed GC): 针对整个新生代和部分老年代的收集(目前只有G1收集器有)
  4. 整堆收集(Full GC): 针对整个JAVA堆和方法区的收集

二、垃圾回收算法

1.标记-清除算法

        过程:将垃圾回收分为两个阶段:先标记,再回收。这里的标记可以是需要回收的对象,也可以反向标记不需要回收的对象。

        缺点:如果存在大量需要标记的对象,那么效率会较低

                  清理后会存在大量不连续的内存碎片,可能导致无法分配大对象,从而导致触发再一次的内存回收。

2.标记-复制算法

        过程:将内存分成两块,只使用其中一块,每次回收前把还存活的对象直接复制到另一块里,然后彻底回收当前的这一块区域。

        优点:实现简单,效率高,解决了内存碎片的问题,大部分商用虚拟机采用此方式。

        缺点:可用内存少了一半,空间浪费大

3.Appel式的标记-赋值算法

        理论:大多数情况下,新生代98%的对象都会在第一轮回收中被回收掉

        过程:新生代内存分为1块Eden区域和2块Survivor区域,1块Eden与1块Survivor的大小比例为8:1,每次只使用1块Eden+1块Survivor区域,回收时把Eden区域和Survivor区域中存活的对象复制到另一块没使用的Survivor区域,假如装不下,就把多出来的对象放到老年代里去。

        优点:内存浪费只有一块很小的Survivor,也就是说利用率达到90%。目前被HotSpot的Serial和ParNew收集器采用。

4.标记-整理算法

        理论:对于老年代,每次回收后对象存活率几乎是100%,不能采用标记-复制的方法。

        过程:标记存活的对象,然后将所有存活的对象移动到内存空间的一端,把另一端的空间清理掉

        优点:相对于标记清除,它整理后的对象访问顺序集中,清除了内存碎片,分配新对象更快,增加了程序吞吐量

        缺点:移动对象时,程序必须暂时停下来等待重新分配的对象地址,导致延迟。

CMS采用标记-清除与标记-整理混合使用的方法,平时使用标记清除,当内存碎片过多影响分配新对象时,就使用一次标记-整理来清掉碎片。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值