JVM虚拟机在判断哪些对象须要回收以后,接下来就是如何回收这些对象的内存。能够把系统内存想象成一个个小方格,jvm使用到的内存和须要收集到内存都散乱分布。如何将须要回收的内存回收,并尽量提升效率和剩余内存的规整?
算法
这个是最基础的算法,顾名思义,这个算法分为两步:安全
复制算法之因此说它是最基础的收集算法,是由于后续的收集算法都是基于这种思路并对其不足进行改进而获得的。数据结构
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了
实现步骤:jvm
在实际应用中,大部分新生代都使用这个算法,实际并不须要缩小一半这么多。IBM公司的专门研究代表,新生代中的对象98%是“朝生夕死”的,因此并不须要按照1∶1的比例来划份内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间。ide
标记-整理算法与新生代不一样,老年代的垃圾回收,通常大部分对象都会存活,若是使用标记-复制操做,不只效率会下降,而且也必须按照1:1的比例来分配内存空间,形成50%的空间浪费。根据老年代的特色,有人提出了另一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象进行清理,而是让全部存活的对象都向一端移动,而后直接清理掉端边界之外的内存线程
这种算法并无什么新的思想,只是根据对象存活周期的不一样将内存划分为几块。
通常是把Java堆分为新生代和老年代,这样就能够根据各个年代的特色采用最适当的收集算法。对象
垃圾收集的第一步,是肯定哪些对象已死,这里使用的是可达性分析算法。第一步:枚举根节点,即肯定可达性分析的GC ROOTS节点。如何根节点可能出现的地方很大,所有都须要扫描一遍,所以可达性分析对执行时间的敏感还体如今GC停顿上,由于这项分析工做必须在一个能确保一致性的快照中进行,——这里“一致性”的意思是指在整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不能够出现分析过程当中对象引用关系还在不断变化的状况,该点不知足的话分析结果准确性就没法获得保证。blog
这点是致使GC进行时必须停顿全部Java执行线程(Sun将这件事情称为“Stop TheWorld”)的其中一个重要缘由,即便是在号称(几乎)不会发生停顿的CMS收集器中,枚举根节点时也是必需要停顿的。进程
HoptSpot虚拟机中采用的是准确式GC,因此当执行系统停顿下来后,并不须要一个不漏地检查完全部执行上下文和全局的引用位置。HoptSpot虚拟机中使用一组称为OopMap的数据结构来达到这个目的的,在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程当中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样,在系统停顿时,就不须要在一一遍历全部对象,只须要从OopMap直接获取根节点就能够了。内存
在OopMap的协助下,HotSpot能够快速且准确地完成GC Roots枚举,但一个很现实的问题随之而来:可能致使引用关系变化,或者说OopMap内容变化的指令很是多,若是为每一条指令都生成对应的OopMap,那将会须要大量的额外空间,这样GC的空间成本将会变得很高。
因此,为了解决这个问题,引入安全点的概念,即:不是全部操做都记录OopMap,只在一些关键点记录。这就意味着,当jvm想要中止运行时,不是马上中止运行,而是等全部线程所有跑到安全点才会真的中止。
这就引入了下一个问题:如何让全部线程都跑到安全点?如今主要有两种方案:抢先式中断(Preemptive Suspension)和主动式中断(VoluntarySuspension)
安全点彷佛完美解决了进程如何进入GC的问题,可是有个前提,全部的线程都要“跑”到安全点才能够,那么若是线程处于Sleep状态或者Blocked状态,这时候线程没法响应JVM的中断请求,“走”到安全的地方去中断挂起,JVM也显然不太可能等待线程从新被分配CPU时间。对于这种状况,就须要安全区域(Safe Region)来解决。
安全区域是指在一段代码片断之中,引用关系不会发生变化。在这个区域中的任意地方开始GC都是安全的。咱们也能够把Safe Region看作是被扩展了的Safepoint。
简单来讲,就是一段代码呗标识为安全区域,线程执行到这里时,会标记线程处于安全区域。那么程序GC时,就无论这个线程,同时这个线程离开安全区域时,若是系统正在GC,也要等待GC完成以后再离开。 简要地介绍了HotSpot虚拟机如何去发起内存回收的问题,可是虚拟机如何具体地进行内存回收动做仍然未涉及,由于内存回收如何进行是由虚拟机所采用的GC收集器决定的,而一般虚拟机中每每不止有一种GC收集器,这个问题再下一篇博客中探讨