关于垃圾回收,首先要解决的问题是 如何知道哪些对象须要回收java
目前有两种算法算法
1 引用计数法多线程
每一个对象上都有一个引用计数,对象每被引用一次,引用计数器就+1,对象引用被释放,引用计数器-1,直到对象的引用计数为0,对象就标识能够回收,并发
可是这个算法有明显的缺陷,对于循环引用的状况下,循环引用的对象就不会被回收jvm
2 root搜索算法spa
在java中,可做为GC Roots的对象包括下面几种:线程
Jvm在肯定是否回收的对象的时候采用的是root搜索算法来实现。code
在root搜索算法的里面,咱们说的引用这里都指定的是强引用关系。所谓强引用关系,就是经过用new 方式建立的对象,而且显示关联的对象对象
Object obj =
new
Object();
以上就是表明的是强引用关系,变量obj 强引用了 Object的一个对象。生命周期
java里面有四种应用关系,从强到弱分别为:
Strong Reference(强引用) –>Weak Reference (弱引用) -> Soft Reference(软引用) – > Phantom Reference(引用)
Strong Reference : 只有在引用对象root不可达的状况下才会标识为可回收,垃圾回收才可能进行回收
Weak Reference :即便在root算法中 其引用的对象root可达到,可是若是jvm堆内存 不够的时候,仍是会被回收,jkd1.2 后,WeakReference类实现弱引用
Soft Reference : 不管其引用的对象是否root可达,在响应内存须要时,由垃圾回收判断是否须要回收,jkd1.2 后,softReference类实现弱引用
Phantom Reference :在回收器肯定其指示对象可另外回收以后,被加入垃圾回收队列,jkd1.2 后,PhantomReference类实现弱引用
二 典型的垃圾回收分算法
1. Mark-Sweep(标记-清除)算法
这是最基础的垃圾回收算法,之因此说它是最基础的是由于它最容易实现,思想也是最简单的。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出全部须要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
标记-清除算法实现起来比较容易,可是有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会致使后续过程当中须要为大对象分配空间时没法找到足够的空间而提早触发新的一次垃圾收集动做。
2. Copying(复制)算法
为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。
这种算法虽然实现简单,运行高效且不容易产生内存碎片,可是却对内存空间的使用作出了高昂的代价,由于可以使用的内存缩减到原来的一半。
很显然,Copying算法的效率跟存活对象的数目多少有很大的关系,若是存活对象不少,那么Copying算法的效率将会大大下降。
3. Mark-Compact(标记-整理)算法
为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep同样,可是在完成标记以后,它不是直接清理可回收对象,而是将存活对象都向一端移动,而后清理掉端边界之外的内存
4. Generational Collection(分代收集)算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不一样的区域。通常状况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特色是每次垃圾收集时只有少许对象须要被回收,而新生代的特色是每次垃圾回收时都有大量的对象须要被回收,那么就能够根据不一样代的特色采起最适合的收集算法。
目前大部分垃圾收集器对于新生代都采起Copying算法,由于新生代中每次垃圾回收都要回收大部分对象,也就是说须要复制的操做次数较少,可是实际中并非按照1:1的比例来划分新生代的空间的,通常来讲是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另外一块Survivor空间中,而后清理掉Eden和刚才使用过的Survivor空间。
而因为老年代的特色是每次回收都只回收少许对象,通常使用的是Mark-Compact算法。
注意,在堆区以外还有一个代就是永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部份内容:废弃常量和无用的类。
三 .典型的垃圾收集器
垃圾收集算法是 内存回收的理论基础,而垃圾收集器就是内存回收的具体实现。下面介绍一下HotSpot(JDK 7)虚拟机提供的几种垃圾收集器
如图展现了不一样分代的收集器,若是两个收集器间存在连线,就说明他们能够搭配使用。
1.Serial/Serial Old
Serial/Serial Old收集器是最基本最古老的收集器,它是一个单线程收集器,而且在它进行垃圾收集时,必须暂停全部用户线程。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优势是实现简单高效,可是缺点是会给用户带来停顿。
2.ParNew
ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。
3.Parallel Scavenge
Parallel Scavenge收集器是一个新生代的多线程收集器(并行收集器),它在回收期间不须要暂停其余用户线程,其采用的是Copying算法,该收集器与前两个收集器有所不一样,它主要是为了达到一个可控的吞吐量。
4.Parallel Old
Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。
5.CMS
CMS(Current Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是Mark-Sweep算法。(其中初始标记和从新标记这两个步骤须要stop the world,并发标记都和并发清除的过程当中,收集器线程能够与用户线程一块儿工做)
6.G1
G1收集器是当今收集器技术发展最前沿的成果,它是一款面向服务端应用的收集器,它能充分利用多CPU、多核环境。所以它是一款并行与并发收集器,而且它能创建可预测的停顿时间模型。
四 内存分配
Java体系中所提倡的自动内存管理最终能够归结为自动化的解决两个问题:给对象分配内存以及回收分配给对象的内存,关于回收内存的这点,如上总结,如今咱们一块儿探讨一下如何给对象分配内存。
分配的规则并非百分百固定的,其细节取决于当前使用哪一种垃圾收集器组合,还有虚拟机中内存相关的参数设置。
注:本篇内容整理自《深刻理解Java虚拟机》