垃圾回收机制,Java很是重要的特性之一,它让开发者无需关注空间的建立和释放,而是以守护进程的形式在后台自动回收垃圾。算法
堆,是在JVM启动时建立的,属于JVM运行时数据区的重要组成部分,主要用来维护运行时数据,如运行过程当中建立的实例对象和数据。若是动态建立的对象没有获得及时回收,持续堆积,最后会致使堆空间被占满,形成内存溢出。设计
Java提供的垃圾回收机制,在后台建立一个守护进程。在内存紧张时自动执行垃圾回收,从而保证程序的正常运行。对象
所谓“垃圾”,指全部再也不存活的对象。进程
常见判断对象是否存活的两种方法:图片
实际上,Java里没有采用这样的方案来断定对象的“存活性”。内存
参考下图,object五、object六、object7为不可达对象,视为“垃圾”,会被垃圾回收器回收 开发
GC Roots自己必定是可达的,从他们出发遍历到的对象才能保证必定可达。 Java里存在如下四种必定可达对象:虚拟机
备注:下述图中,黑色表明垃圾对象,灰色表明存活对象,绿色表明空白空间。it
第一步,标记,利用可达性遍历堆内存时,把存活对象和垃圾对象进行标记(以下图所示) io
第二步,清理,把标记为垃圾对象进行清空,释放所占空间
总结,该方案简单方便,但容易产生内存碎片。
基于标记-清理方案,在清理时将全部存活的对象集中到一块儿,造成一个连续使用的内存空间,以下图所示:
总结,标记-清理、标记-整理两种方案,适合存活对象多、垃圾少的状况,只须要清理较少的垃圾,挪动一下存活对象就能够了。
这种比较粗暴,将堆内存一分为二成两部分,一段时间内只容许在其中一块内存上进行分配,当该内存块被分配完后,则执行垃圾回收:把全部存活对象复制到另外一块内存里,而后直接清空当前内存。
总结,这种作法不易产生碎片,简单粗暴;可是,它只容许一段时间内只能使用一部份内存,超过这部份内存的话就有频繁的复制清空。这种方案适合存活对象少、垃圾多的状况,在复制只需移动少许的存活对象。
上述讲到三种内存回收方案,那Java中是如何选择利用这三种回收算法呢?
Java 堆空间(Heap)分红三部分,这三部分存储三类数据:
总结,常规的Java堆至少包括了新生代和老年代两块内存区域:
对于新生代区域,因为每次GC都会有大量新对象死去,存活的较少。所以采用复制回收机制,GC时只把少数存活的对象复制过去便可。
复制算法设计:
缺陷:至关于只有一半的内存可用,对于新生代而言,新对象会频繁地进行建立,若是只有一半的可用内存,会持续 不断地进行垃圾回收工做,影响了程序的正常运行。
最开始使用9的内存,当9快满时执行复制回收机制,把9中存活的对象复制到1区,并清空9区。
缺陷:因为内存空间比例相差较大,当把9区存活的对象复制到1区时,颇有可能1区放不下,此时不得不把对象移到老年区。这就意味着,可能会有一部分并不老的9区对象因为1区放不下而被放到老年区,破坏了老年区的规则。
工做原理:
老年代通常存放存活时间较久的对象,因此每次GC时,存活对象多,每次只要少数对象被回收。所以,根据不一样回收机制的特色,这里选择标记整理回收机制,仅仅经过少许地移动对象就能清理垃圾,并且不存在内存碎片。