前言
JAVA虚拟机的垃圾收集器是虚拟机内存的清道夫,它的存在让JAVA开发人员能将更多精力投入到业务研发上。了解垃圾收集器,并利用好这个工具,能更好的保障服务稳定性。这篇文章通过分析JAVA虚拟机内存模型,介绍垃圾收集器常用算法和收集器类别,使得垃圾收集器的配置和使用变得不再遥不可及。
JAVA虚拟机内存模型
JAVA虚拟机内存可以划分为:虚拟机栈、本地方法栈、JAVA堆内存、方法区(包含运行时常量池)、程序计数器、直接内存。
虚拟机栈
虚拟机栈是线程私有的,生命周期跟线程相同。也就是说一个线程被创建后,虚拟机为其分配了一个独立的栈帧来存储线程的局部变量、操作数、动态链接、方法出口等信息,当线程结束后,该栈帧也会被回收清理。
本地方法栈
本地方法栈是虚拟机的native方法执行期间使用的一个栈帧。
JAVA堆内存
堆内存是被所有线程共享的一块区域,用来存放对象实例和数组,属于内存中最大的一块区域,也是垃圾收集的主要区域。从垃圾收集的角度看,堆内存经常分为新生代和老年代。
方法区
方法区也是被所有线程共享的一块区域,用来存储被虚拟机加载的类信息、常量、静态变量、JIT编译后代码等数据。也可以成为永久代。
程序计数器
程序计数器是线程私有的,作为当前线程所执行的字节码的行号指示器,每个线程有一个程序计数器,用于记录CPU切换线程时记录当前线程的执行位置,以便下次继续从当前位置往下执行。
直接内存
这块不属于JAVA虚拟机内存,但使用频繁,也可称之为“堆外内存”
JAVA虚拟机垃圾收集器
根据上述对JAVA虚拟机内存区域模型的介绍,我们知道JAVA程序中的对象实例都存储在JAVA堆内存中,因此垃圾收集主要也是针对堆内存进行。为了更好的管理JAVA对象实例,并结合对象实例的生存时间长短,JAVA虚拟机将堆内存分为新生代和老年代,分别存储刚创建不久的对象和存活较长时间的对象实例,并采用分代收集的策略分别回收新生代和老年代的内存。
内存分配与回收策略
- 1、 分代收集思路。根据JAVA对象的生存周期特点,虚拟机将堆内存分为新生代和老年代,并分别采用新生代和老年代的垃圾回收策略。
- 2、 新生代细分为Eden区和两个Survivor区(即From区和To区)。大多数新生对象创建频繁,且存活时间短,为了提高新生代区域垃圾收集效率,新创建的对象存放在Eden区,当Eden区快满的时候,虚拟机对其触发一次Minor GC,将新生代存活对象移动到From区,原来From区的对象根据存活年龄决定放到To区还是老年代,然后清空Eden区和From区,接着将To区对象全部移到From区。
- 3、 大对象直接进入老年代,可以配置新生代对象的最大值,对象超过这个值就直接进入老年代。
- 4、 发起Minor GC前,会先判断老年代最大可用连续空间是否大于新生代对象占用的空间,如果小于或不允许冒险,则触发一次Full GC。
垃圾收集算法(3种基本算法)
- 1、 复制算法。针对于新生代的垃圾收集算法。当新生代Eden区快满的时候,将Eden区对象复制到From区,将From区对象根据存活年龄决定复制到To区还是到老年代,然后清除Eden区和From区,接着将To区对象复制到From区。
- 2、 标记-清除算法。垃圾收集算法标记出需要回收的对象,标记完成后直接统一回收。垃圾收集器使用可达性分析来判断哪些对象是否存活,通过设置一系列GC Roots节点(包括栈、方法区中的静态属性和常量所引用的对象,以及本地方法栈中引用的对象),从这类节点往下搜索,当对象不在GC Root节点的引用链上时,说明对象不可达,可以被回收。
- 3、 标记-整理算法。垃圾收集算法标记出需要回收的对象,标记完成后将存活对象往内存的一端移动,然后直接清理掉端边界以外的内存。
常用垃圾收集器
由于虚拟机中的垃圾收集是分代收集的,新生代和老年代的垃圾收集策略不太一样,所以一般是使用针对新生代和老年代的垃圾收集器组合。
- 1、 Serial GC。新生代收集器,采用复制算法,用于Client客户端新生代垃圾收集,针对内存占用较少的应用进行垃圾收集。
- 2、 Serial Old GC。老年代收集器,采用标记-整理算法,用于Client客户端老年代垃圾收集,针对内存占用较少的应用进行垃圾收集。
- 3、 Parallel Scavenge GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾,可以设置垃圾收集器的吞吐量,还可以设置自动适配调节吞吐量。
- 4、 Parallel New GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾。
- 5、 Parallel Old GC。老年代收集器,采用标记-整理算法,并行收集老年代内存垃圾。
- 6、 CMS GC。老年代收集器,采用标记-清除算法,并行收集老年代内存垃圾,不整理内存。由于在执行垃圾收集期间不中断业务线程,所以容易产出“浮动垃圾”,导致Full GC。可以通过设置参数来触发内存整理任务。
- 7、 G1 GC。不再将堆内存区分新生代和老年代,而是将堆内存看作若干个均分小区域,并对最空闲的内存区域进行标记和回收。适用于大内存的应用。
原文地址:http://blog.51cto.com/andrewli/2115644