垃圾收集器与内存分配策略
概述
GC当前高度自动化,but当GC成为系统高并发瓶颈时,就需要对GC进行必要的监控和调节。针对JVM,GC主要针对**堆**。通过**垃圾收集器**,按照**垃圾收集算法**,对内存进行分配和回收。判断对象存亡
- **引用计数法reference counting** 有引用,计数器加1,引用失效,计数器减1,计数器为0的对象不再被使用的。但是难以解决Java中的互相循环引用问题。 - **根搜索算法GC root tracing** 以GC Root为根节点,向下搜索,无引用链的对象,证明不可用。 可作为GC Root的对象有: - 虚拟机栈引用对象 - 方法区中类静态属性引用对象 - 方法区常量引用对象 - JNI引用对象-
引用
传统定义:如果引用类型存储的数值代表另一块内存的起始地址,就称这块内存代表一个引用。
JDK1.2以后,引用进行了划分:- 强引用,普遍存在
- 软引用,内存溢出之前,进行回收,仍然溢出,抛出异常,参照SoftReference
- 弱引用,下一次GC之前存活,WeakReference
- 虚引用,主要是获得GC通知,不影响生存周期。
-
对象缓刑
第一次标记,GC Root标记的不可用对象,并且判断对象是否覆盖finalize()或finalize()方法已被JVM调用过。如果是,标记为没有必要执行。
第二次标记,如果判定为有必要执行,则将此对象放到一个F-Queue中,JVM自动启动一个低优先级线程处理。为了防止死循环或执行缓慢等意外情况,GC还会对F-Queue中对象进行第二次小规模标记。如果对象仍然没有重新与引用链上建立关联,则GC掉。 -
回收方法区
性价比比堆低很多。主要回收“废弃常量”,对于hotspot虚拟机,提供了参数进行配置,尤其是大量使用反射,动态代理,CGLib等bytecode框架时,都需要JVM具备类卸载功能,保证永久代不会溢出。判断“废弃常量”需满足:- 该类所有实例被回收
- 加载该类的classloader被回收
- 该类对象的java.lang.class对象没有任何引用,防止反射
垃圾收集算法
- 标记-清除算法Mark-Sweep 标记待清除对象,参照上节**对象缓刑**,清除对象,缺点较明显: - 效率低 - 容易产生大量不连续内存碎片,当程序需要分配大对象时并无足够连续内存时,提前触发下次GC-
复制算法Coping
- 内存分两块,一块用完时将存活对象复制到另一块,并清理当前块。JVM都采用这种算法回收新生代。
- 98%对象朝生夕死,HotSpot虚拟机将内存分为一块Eden(80%),两块Survivor(20%),每次使用Eden和其中一块survivor。回首时,将存放对象放到另一块survivor上。当多余10%内存对象存活时,依赖老年代内存,进行分配担保。 -
标记-整理算法
复制算法,对象存活率较高时,需要执行较多的复制操作,效率较低。标记整理算法,是标记出存活对象,GC时,让存活对象向内存一端移动,然后直接清理掉端边界以外内存。 -
分代收集算法
当前商业JVM都采用分代收集,把Java堆分为新生代和老年代。新生代中,存活对象少,采用复制算法。老年代对象存活率高,没有额外空间进行分配担保,必须使用“标记-清理”或“标记-整理”算法进行回收。
垃圾收集器
> 根据收集算法,有多种收集器的实现,没有最好,只有最合适-
Serial收集器
单线程,暂停其它工作线程,依然是JVM运行在Client模式的默认收集器,简单而高效。在用户桌面应用场景中,收集几十甚至上百M的新生代,停顿时间会控制在100毫秒以内,可接受。 -
ParNew收集器
Serial收集器的多线程版本,单核效果比Serial低。 -
Parallel Scavenge收集器
新生代收集器,复制算法,“吞吐量优先”,可配置停顿时间和吞吐量大小,可打开GC自适应调节策略,自动调节新生代,Eden与Subvivor区比例。 -
Serial Old收集器
是Serial收集器的老年代版本,单线程,“标记-整理”算法 -
Parallel Old收集器
多线程,“标记-整理”,注重吞吐量及CPU资源敏感的场合,优先考虑Parallel Scavenge收集器加Parallel Old收集器 -
CMS收集器
Concurrent Mark Sweep,最短回收停顿时间,重视响应速度,“标记-清除”,分4部:
- 初始标记
- 并发标记
- 重新标记
- 并发清除
其中,初始和重新标记,单线程,缺点:
- CPU资源敏感
- 无法处理浮动垃圾
- 标记清除算法,清理不及时,触发Full GC -
G1收集器
Garbage First,“标记-整理”,收集毫秒级,将整个Java堆分队多个region,维护一个优先列表,最大限度提升收集效率
I am a slow walker, but I never walk backwards.