垃圾收集 (Garbage Collection) 机制是Java语言的一大优势特性, 为充分榨取JVM性能, 避免系统因垃圾收集不及时导致的OOM (OutOfMemory, 内存溢出)问题, 或内存饱和出现无法响应用户请求的情况, 就需要根据服务器配置及应用复杂度对GC策略进行优化, 以确保系统正常运行.
1 JVM中Java对象的分类
JVM根据运行于其中的对象的生存时间, 将它们分为3种, 并分别存放在JVM的不同内存区域中. 这种对象存放空间的管理方式叫做Generation管理方式.
(1) Young Generation (新生代, 又称年轻代): 用于存放"早逝"对象(即瞬时对象), 一般的Java应用中, 80%的对象都是"朝生息灭"的, 比如在创建对象或调用方法时使用的临时对象或局部变量.
(2) Tenured Generation (老年代): 用于存放"驻留"对象(即被引用较长时间的对象). 往往体现为一个大型程序中的全局对象或长时间被使用的对象.
(3) Perm Generation (永久代): 用于存放"永久"对象. 这些对象管理着运行于JVM中的类和方法.
2 JVM的GC类型及触发条件
2.1 Young GC
又叫Minor GC(次收集), Young GC经常发生, 且其每次消耗的时间较短.
—— 它只对Young Generation中的对象进行垃圾收集.
触发条件:
在Young Generation(新生代)的Eden区的空间不足以容纳新生成的对象时执行, 同时会将 Eden 区与 From Survivor 区中尚且存活的对象移动至空闲的 To Survivor 区中.
—— 程序运行过程中, 始终有一个 Survivor 区是完全处于空闲状态的, 如果不是, 说明应用程序出现故障了.
2.2 Full GC
又叫Major GC(主收集), 是对整个Java Heap中的对象(包括永久代/元空间)进行垃圾收集.
Full GC操作耗时久, 对系统的性能影响较大, 因此在 JVM 的调优中, 很多工作是针对 Full GC 的调优 —— 要尽可能减少Full GC的频率.
Full GC 是一种"昂贵"的垃圾收集方式, 它要对整个Heap进行垃圾收集, 并做一定的空间整理, 这会使Stop-The-World的时间变长.
Full GC的触发条件:
(1) 年老代(Tenured)空间不足:
通过Minor GC后进入老年代的对象的体积大于老年代的可用空间;由Eden块、From Space块向To Space复制存活对象时, 它们的体积大于To Space的大小, 系统就会把这些对象转存到老年代, 而老年代的可用空间小于这些对象的体积.
(2) System.gc()方法被显式调用, 系统建议执行Full GC, 但并不会立即执行 —— 非常影响程序性能, 建议禁止使用;
(3) 上一次GC之后Heap中各个区域空间的动态变化.
3 Java对象生成时的内存申请过程
(1) JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域;
(2) 当Eden区空间足够时, 内存申请结束. 否则执行下一步;
(3) JVM 试图释放在Eden区中所有不活跃的对象(即