JVM--垃圾收集算法

打印 上一主题 下一主题

主题 511|帖子 511|积分 1533

1.分代收集理论

           垃圾收集算法可以划分为“引用计数式垃圾收集”(ReferenceCounting GC)和“追踪式垃圾收集”(Tracing GC)两大类,本次仅仅讨论踪式垃圾收集
  
  谈到垃圾收集 ,首先先了解分代的收集理论:
         当前贸易假造机的垃圾收集器,大多数都遵循了   “   分代收集   ”   (   Generational Collection   )   的理论进行计划,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上:            1)弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。
         2)强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。
  由据前两条假说逻辑推理得出的隐含推论:
         3)跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。
  
            强分代假说和弱分代假说:这两个分代假说共同奠基了多款常用的垃圾收集器的同等的计划原则:收集器应该将Java堆划分出不同的区域,然后将接纳对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。显而易见,假如一个区域中大多数对象都是朝生夕灭,难以熬过垃圾收集过程的话,那么把它们会合放在一起,每次接纳时只关注怎样保留少量存活而不是去标志那些大量将要被接纳的对象,就能以较低代价接纳到大量的空间;假如剩下的都是难以消亡的对象,那把它们会合放在一块,假造机便可以使用较低的频率来接纳这个区域,这就同时兼顾了垃圾收集的时间开销和内存的空间有效利用。
  
  跨代引用假说是怎样产生的?其定义的理解呢?跨代引用假说又怎样办理产生的题目的呢?
          怎样产生:那么假如要现在进行一次只局限于新生代区域内的收集(Minor GC),但新生代中的对象是完全有大概被老年代所引用的,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的精确性,反过来也是一样[3]。遍历整个老年代所有对象的方案虽然理论上可行,但无疑会为内存接纳带来很大的性能负担。为了办理这个题目,就需要对分代收集理论添加第三条经验法则(跨代引用假说)
          定义:这实在是可根据前两条假说逻辑推理得出的隐含推论:存在互相引用关系的两个对象,是应该倾向于同时生存大概同时消亡的。举个例子,假如某个新生代对象存在跨代引用,由于老年代对象难以消亡,该引用会使得新生代对象在收集时同样得以存活,进而在年龄增长之后提升到老年代中,这时跨代引用也随即被消除了。
          产生的题目及怎样办理:依据这条假说,我们就不应再为了少量的跨代引用去扫描整个老年代,也不必浪费空间专门记录每一个对象是否存在及存在哪些跨代引用,只需在新生代上建立一个全局的数据布局(该布局被称为“记忆集”,Remembered Set),这个布局把老年代划分成多少小块,标识出老年代的哪一块内存会存在跨代引用。今后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被参加到GCRoots进行扫描。虽然这种方法需要在对象改变引用关系(如将自己大概某个属性赋值)时维护记录数据的精确性,会增加一些运行时的开销,但比起收集时扫描整个老年代来说仍然是划算的。
  
  新生代和老年代的划分:
          把分代收集理论具体放到现在的商用Java假造机里,计划者一般至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域[2]。顾名思义,在新生代中,每次垃圾收集时都发现有大批对象死去,而每次接纳后存活的少量对象,将会逐步提升到老年代中存放。
  2.垃圾收集的算法

   1.标志-清除算法

  

  定义:最早出现也是最基础的垃圾收集算法是“标志-清除”(Mark-Sweep)算法,在1960年由Lisp之父John McCarthy所提出。如它的名字一样,算法分为“标志”和“清除”两个阶段:首先标志出所有需要接纳的对象,在标志完成后,统一接纳掉所有被标志的对象,也可以反过来,标志存活的对象,统一接纳所有未被标志的对象。标志过程就是对象是否属于垃圾的判断过程,
  长处
          简单容易实现
  缺点:
          1.实行效率不稳定:
                  假如Java堆中包含大量对象,而且此中大部分是需要被接纳的,这时必须进行大量标志和清除的动作,导致标志和清除两个过程的实行效率都随对象数量增长而降低;
          2.内存空间的碎片化:
                  标志、清除之后会产生大量不连续的内存碎片,空间碎片太多大概会导致当以后在程序运行过程中需要分配较大对象时无法找到充足的连续内存而不得不提前触发另一次垃圾收集动作。
  
  2.标志-复制算法

  

  定义:标志-复制算法常被简称为复制算法。为了办理标志-清除算法面临大量可接纳对象时实行效率低和办理内存空间的碎片化的题目,1969年Fenichel提出了一种称为“半区复制”(Semispace Copying)的垃圾收集算法,它将可用内存按容量划分为大小相称的两块,每次只使用此中的一块。当这一块的内存用完了,就将还存在世的对象复制到另外一块上面,然后再把已使用过的内存空间一次清算掉
          假如内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可接纳的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存接纳,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按次序分配即可。
  长处
          实现简单,运行高效,不会产生碎片化题目
  缺点
          这种复制接纳算法的代价是将可用内存缩小为了原来的一半,空间浪费未免太多了一点。
  办理空间浪费题目
          新生代中的对象有98%熬不过第一轮收集。因此并不需要按照1∶1的比例来划分新生代的内存空间。
          在1989年,Andrew Appel针对具备“朝生夕灭”特点的对象,提出了一种更优化的半区复制分代策略,现在称为“Appel式接纳”。HotSpot假造机的Serial、ParNew等新生代收集器均接纳了这种策略来计划新生代的内存布局。
          Appel式接纳的具体做法是把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配内存只使用Eden和此中一块Survivor。发生垃圾搜集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上,然后直接清算掉Eden和已用过的那块Survivor空间。
          HotSpot假造机默认Eden和Survivor的大小比例是8∶1,也即每次新生代中可用内存空间为整个新生代容量的90%(Eden的80%加上一个Survivor的10%),只有一个Survivor空间,即10%的新生代是会被“浪费”的。(浪费指在任何一次Minor GC(针对新生代的垃圾收集)过程中,都会有一个Survivor区是空的,不到场当前的内存分配和接纳。这个空的Survivor区占据了新生代总容量的10%,因此被称为“浪费”的空间。)
          当然,98%的对象可被接纳仅仅是“普通场景”下测得的数据,任何人都没有办法百分百保证每次接纳都只有不多于10%的对象存活,因此Appel式接纳还有一个充当罕见情况的“逃生门”的安全计划,当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实际上大多就是老年代)进行分配包管(Handle Promotion)。
  现在现状:现在的商用Java假造机大多都优先接纳了这种收集算法去接纳新生代
  
  3. 标志-整理算法

  

  产生背景
          标志-复制算法在对象存活率较高时就要进行较多的复制利用,效率将会降低。更关键的是,假如不想浪费50%的空间,就需要有额外的空间进行分配包管,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。
  定义:
          针对老年代对象的存亡特征,1974年Edward Lueders提出了另外一种有针对性的“标志-整理”(Mark-Compact)算法,此中的标志过程仍然与“标志-清除”算法一样,但后续步骤不是直接对可接纳对象进行清算,而是让所有存活的对象都向内存空间一端移动,然后直接清算掉边界以外的内存
          标志-清除算法与标志-整理算法的本质差别在于前者是一种非移动式的接纳算法,而后者是移动式的。
  长处
          实用于老年代,保证了老年代存活久,需要空间大的题目
  缺点
          假如移动存活对象,尤其是在老年代这种每次接纳都有大量对象存活区域,移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的利用,而且这种对象移动利用必须全程停息用户应用程序才气进行
  办理缺点的方案
           是让假造机平常多数时间都接纳标志-清除算法,临时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再接纳标志-整理算法收集一次,以获得规整的内存空间。前面提到的基于标志-清除算法的CMS收集器面临空间碎片过多时接纳的就是这种处理办法。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表