jvm管理的内存叫堆,初始分配和最大分配的内存由-Xms-Xmx指定;
GC基本收集算法
- 复制:将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A;
因为只访问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去访问死对象,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存;- 标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃对象进行回收处理,该算法遍历整个空间的成本较大暂停时间随空间大小线性增大,而且整理后堆里的碎片很多;
- 标记整理(mark-sweep-compact):综合了上述两者的做法和优点,先标记活跃对象,然后将其合并成较大的内存块;
分代
根据对象的生命周期长短,把堆分成3个代:Young、Old、Permanent
Young,年轻代,大部分对象都是朝生暮死,随生随灭的,选择了复制算法;
Young分为3个区域,Eden所有新建对象都会存在于该区、两个Survivor区用来实施复制算法;
每次复制就是将Eden和第一块Survivor的活对象复制到第二块,然后清空Eden与第一块Survivor;
Eden与Survivor的比例由-XX:SurvivorRatio=设置,默认为32;Old,年老代,Young的对象如果能够挺过数次收集,就会进入年老代。其使用标记清理算法;
-XX:MaxTenuringThreshold=设置熬过年轻代多少次收集后移入年老代;
可以使用-XX:+PrintTenuringDistribution查看Permanent,持久代。装载Class信息等基础数据,默认64M,通过-XX:MaxPermSize=设置;
GC用较高的频率对Young进行扫描和回收,称为minor collection;同时对Young和Old的收集称为major collection;
System.gc()会引发major collection,使用-XX:+DisableExplicitGc禁止它,或设为CMS并发-XX:+ExplicitGCInvokesConcurrent
GC触发
- Minor GC(新生代回收)的触发条件比较简单,Eden空间不足就开始进行Minor GC回收新生代。
- Full GC(老年代回收,一般伴随一次Minor GC)则有几种触发条件:
- 老年代空间不足
- PermSpace空间不足
- 统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间