Java 虚拟机提供了一系列的垃圾回收机制(Garbage Collection),又或者说是垃圾回收器(Garbage Collector),其中常见的垃圾回收器如下:
Serial GC(Serial Garbage Collection):第一代GC,是1999年在JDK1.3中发布的串行方式的单线程GC。一般适用于 最小化地使用内存和并行开销的场景。
Parallel GC(Parallel Garbage Collection):第二代GC,是2002年在JDK1.4.2中发布的,相比Serial GC,基于多线程方式加速运行垃圾回收,在JDK6版本之后成为Hotspot VM的默认GC。一般是最大化应用程序的吞吐量。
CMS GC(Concurrent Mark Sweep Garbage Collection ):第二代GC,是2002年在JDK1.4.2中发布的,相比Serial GC,基于多线程方式加速运行垃圾回收,可以让应用程序和GC分享处理器资源的GC。一般是最小化GC的中断和停顿时间的场景。
G1 GC (Garbage First Garbage Collection):第三代GC,是JDK7版本中诞生的一个并行回收器,主要是针对“垃圾优先”的原则而诞生的GC,也是时下我们比较新的GC。
在常见的垃圾回收中,我们一般采用引用计数法和可达性分析两种方式来确定垃圾是否产生,其中:
引用计数法:在Java中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。
可达性分析(根搜索算法):为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。
一般来说,当成功区分出内存中存活对象和死亡对象之后,GC接着就会执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够可用的内存空间为新的对象分配内存。
目前,在JVM中采用的垃圾收集算法主要有:
标记-清除算法(Mark-Sweep ): 最基础的垃圾回收算法,分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。
复制算法(Copying): 为了解决Mark-Sweep算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying算法的效率会大大降低。
标记-压缩算法(Mark-Compact): 为了避免缺陷而提出。标记阶段和Mark-Sweep算法相同,标记后不是清理对象,而是将存活对象移向内存的一端,然后清除端边界外的对象。
增量算法(Incremental Collecting): 也可以成为分区收集算法(Region Collenting),将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收. 这样做的好处是可以控制一次回收多少个小区间 , 根据目标停顿时间, 每次合理地回收若干个小区间(而不是整个堆), 从而减少一次GC所产生的停顿。
分代收集算法(Generational Collenting): 是目前大部分JVM所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将GC堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。
更多关于“java培训”的问题,欢迎咨询千锋教育在线名师。千锋教育多年办学,课程大纲紧跟企业需求,更科学更严谨,每年培养泛IT人才近2万人。不论你是零基础还是想提升,都可以找到适合的班型,千锋教育随时欢迎你来试听。