[TOC]java
通常来讲,每一个对象对应一个计数器,建立对象时,将其计数器置0算法
当对象呗赋予任意变量时,引用计数器每次加1.优化
引用变量出了做用域后,该引用变量所引用的对象的计数器减1.spa
一旦引用计数器为0,对象就知足垃圾收集的条件
<br/>设计
优势:基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜必须实时运行的程序。指针
缺点:引用计数器增长了程序执行的开销,由于每次对象赋予给新的变量,计数器加1,而每次引用变量出了 做用域后,该引用的对象的计数器减1code
还没法解决环形引用对象
Class A(){ public B b = null; } Class B(){ public A a = null; } public void test(){ A a = new A(); B b = new B(); a.b=b; b.a = a }
mutator:除了垃圾收集器以外的部分,好比说咱们的应用程序自己。职责(分配内存),read(从内存中读取内容),write(将内容写入内存)进程
collector:回收再也不使用的内存,供mutator 使用new分配内存图片
mutator roots:通常指的是分配在堆内存以外,能够直接被mutator直接访问到的对象
标记阶段:collector从mutator根对象开始进行遍历,能被mutator roots访问到的对象都打上一个标识,记录为可达对象
清除阶段:collector对内存从头至尾进行线性变量,若是某个对象没有标记为可达对象,就将其回收
从上图咱们能够看到,在Mark阶段,从根对象1能够访问到B对象,从B对象又能够访问到E对象,因此B,E对象都是可达的。同理,F,G,J,K也都是可达对象。到了Sweep阶段,全部非可达对象都会被collector回收。同时,Collector在进行标记和清除阶段时会将整个应用程序暂停(mutator),等待标记清除结束后才会恢复应用程序的运行
<br/>
缺点:标记-清除算法的比较大的缺点就是垃圾收集后有可能会形成大量的内存碎片,像上面的图片所示,垃圾收集后内存中存在三个内存碎片,假设一个方格表明1个单位的内存,若是有一个对象须要占用3个内存单位的话,那么就会致使Mutator一直处于暂停状态,而Collector一直在尝试进行垃圾收集,直到Out of Memory。暂停整个应用
将堆内存分红两个相同空间,从根(相似于前面的有向图起始顶点)开始访问每个关联的可达对象,将空间A的所有可达对象复制到空间B,而后一次性回收空间A。对于该算法而言,由于只需访问全部的可达对象,将全部的可达对象复制走以后就直接回收整个空间,彻底不用理会不可达对象,因此遍历空间的成本较小,但须要巨大的复制成本和较多的内存。
<br/>
缺点:须要两倍内存空间。
优势:不会出现碎片
此算法结合了“标记-清除”和“复制”两个算法的优势。也是分两阶段,第一阶段从根节点开始标记全部被引用对象,第二阶段遍历整个堆,把清除未标记对象而且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
<br/>
优势:避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
缺点:暂停整个应用
基础还是传统的标记-清除和复制算法。设计一个多进程的运行环境,好比用一个进程执行垃圾收集工做,另外一个进程执行程序代码。这样一来,垃圾收集工做看上去就仿佛是在后台悄悄完成的,不会打断程序代码的运行。
<br/>
缺点:垃圾收集器在第一阶段中辛辛苦苦标记出的结果极可能被另外一个进程中的内存操做代码修改得面目全非,以致于第二阶段的工做没有办法开展。---------解决办法: 优化算法
优势:垃圾收集工做看上去就仿佛是在后台悄悄完成的,不会打断程序代码的运行。
新生代
新生代包括两个区:Eden区和Survivor区,其中Survivor区通常也分红两块,简称Survivor1 Space 和 Survivor2 Space (或者From Space 和 To Space)。新生代一般存活时间较短,所以基于标记清除复制算法来进行回收,扫描出存活的对象,并复制到一块新的彻底未使用的空间中,对应于新生代,就是在Eden和From或To之间copy。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从eden到Survior,最后到旧生代。
回收机制:复制回收
老年代
在垃圾回收屡次,若是对象仍然存活,而且新生代的空间不够,则对象会存放在老年代。
在老年代采用的是 标记清除压缩算法。由于老年代的对象通常存活时间比较长,每次标记清除以后,会有不少的零碎空间,这个就是所谓的浮动垃圾。当老年代的零碎空间不足以分配一个大的对象的时候,就会采用压缩算法。在压缩的时候,应用须要暂停。
回收机制:标记-压缩
持久代
这部分空间主要存放java方法区的数据以及启动类加载器加载的对象。这一部分对象一般不会被回收。因此持久代空间在默认的状况下是不会被垃圾回收的。
回收机制:不会被回收
首先想eden区申请分配空间,若是空间够,就直接进行分配,不然进行一次Minor GC。minor GC 首先会对Eden区的对象进行标记,标记出来存活的对象。而后把存活的对象copy到From空间。若是From空间足够,则回收eden区可回收的对象。若是from内存空间不够,则把From空间存活的对象复制到To区,若是TO区的内存空间也不够的话,则把To区存活的对象复制到老年代。若是老年代空间也不够(或者达到触发老年年垃圾回收条件的话)则触发一次full GC。Minor GC通常状况下,当新对象生成,而且在Eden申请空间失败时,就好触发Minor GC,堆Eden区域进行GC,清除非存活对象,而且把尚且存活的对象移动到Survivor区。而后整理Survivor的两个区。Full GC对整个堆进行整理,包括Young、Tenured和Perm。Full GC比Scavenge GC要慢,所以应该尽量减小Full GC。有以下缘由可能致使Full GC