rainyzz's blog

Java的内存回收总结

说到垃圾回收首先要说一下JVM的内存机制,垃圾回收主要回收的是JVM中堆的内存,堆中主要存储的是各种类的实例,占了Java程序使用内存的绝大部分。当前Java内存回收使用的分代回收机制,将内存分为新生代,老年代和永久代,针对不同的代使用不同的回收策略。

##内存回收算法
主要的回收算法包括标记-清除算法,复制算法,标记-整理算法。

###标记-清除算法(Mark-Sweep)
算法分为标记和清除两个阶段,在标记阶段,标记出所有需要回收的对象,在标记完成后统一进行回收。

其主要缺点是标记和清除效率都不高,而且会导致大量的内存碎片,导致重新的垃圾收集和内存整理。

###复制算法(Copying)
算法将可用内存分为相等的两部分,每次使用其中一块,当内存使用完了,将还存活的对象复制到另一块内存中,将原先使用的内存块直接清除。

其主要缺点是将可用内存的空间缩小到了原来的一半。

###标记-整理算法(Mark-Compact)
算法与标记-清除算法在标记阶段相同,只不过后续的操作是将标记存活的对象移向内存的一端,然后将另一端一次性清除。

###分代收集
当前主流的虚拟机都采用分代收集,对新生代和老年代采取不同收集策略,新生代存活对象较少,多采用复制算法,老年代存活较多,多采用标记-清除和标记-整理算法。

##具体的垃圾收集器
在JDK1.7中的HotSpot虚拟机中包含了期中垃圾收集器,每种垃圾收集器都有其特殊的使用场景。这七种收集器包括Serial, PairNew, Parallel Scavenge, CMS, Serial Old, Parallel Old, G1。

##Serial
最基本的收集器,单线程收集器,其进行工作的时候其他所有线程都会暂停,直到其工作结束,收集一百兆左右的内存停顿时间可以控制在100毫秒左右,对于简单收集还是比较高效的。

虚拟机在Client模式下的默认新生代收集算法。

##ParNew(Parallel New)
Serial收集器的多线程版本,有效利用多CPU,但是单CPU性能不如Serial,而且Serial和ParNew是唯二的能与CMS配合的收集器。

ParNew是Server模式下的默认新生代收集算法。

##Parallel Scavenge
新生代收集器,复制算法,并行多线程,其主要关注吞吐量而不是停顿时间。

吞吐量 = 用户代码时间 / (用户代码时间 + 收集时间)

停顿时间主要影响用户体验,而高吞吐量有助于CPU密集程序高效利用CPU计算。

##Serial Old
Serial的老年代版本,使用标记-整理算法。

主要在Client模式使用。在Server模式下可以与Parallel Savenge配合使用,也需要作为CMS的后备使用。

##Parallel Old
Parallel Savenge的老年代版本。采用标记-整理算法。

##CMS(Concurrent Mark Sweep)
其设计目的是获取最短停顿时间。标记-清除算法,并发收集,低停顿。

##G1(Garbage First)
当前垃圾收集的最前沿。面向Server端,并行并发,充分利用多CPU多核。

可以建立可预测的停顿时间模型。

其将Java堆分为大小相等的区域,老年代新生代不再物理隔离,都是一系列区域的集合。

G1当前性能在许多地方还比不上CMS,不过随着对G1的不断改进,其性能也会达到令人满意的结果。

##收集器的并发(Concurrent)与并行(Parallel)
并发指收集和用户代码执行可以同时进行,并行指收集时用户代码执行停止,使用多线程进行收集。

##JVM相关
Client默认值:Serial + Serial Old
Server默认值:Parallel Scavenge + Serial Old

常用收集器
UseParNew:ParNew + Serial Old
UseConcMarkSweepGC:ParNew + CMS + Serial Old
UseParallelOldGC:Parallel Scavenge + Parallel Old