08、JVM实战:内存分配策略:理论

08–内存分配策略–理论


1、介绍

*

Java虚拟机将堆内存划分为新生代、老年代和永久代,永久代是HotSpot虚拟机特有的概念,它采用永久代的方式来实现方法区,其他的虚拟机实现没有这一概念,而且在JDK 1.8中HotSpot已经"去永久化",把原本放在永久代的字符串常量池移出。永久代主要存放常量、类信息、静态变量等数据,与垃圾回收关系不大,新生代和老年代是垃圾回收的主要区域。

2、新生代(Young)

2.1、介绍

1、 新创建的对象在Eden区分配,如果对象是大对象除外,大对象直接进入老年代;
2、 新生代对象朝生夕死,存活率很低,在新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,回收效率很高;
3、 新生代采用复制算法来回收新生代;
4、 当Eden区没有足够的空间进行分配时,虚拟机将发起一次MinorGC;

2.2、新生代结构

新生代由Eden区,from区,to区组成。
默认比例为8:1:1。

2.3、Minor GC触发条件

一旦新创建的对象在eden区放不下的时候,这个时候就触发1次Minor GC。

2.4、新生代中对象的变化

新创建对象,如果是大对象,进入老年代;小对象进入eden区

随着创建对象的增多,eden区空闲的内存慢慢变少,一旦新创建的对象在eden区放不下的时候,这个时候就触发1次Minor GC。

第1次Minor GC:
1、 将eden区没有存活的对象,标记清除掉将eden存活的对象,放到to区;
2、 如果to区不够大,放不下,需要依赖老年代进行分配担保,将这些对象存放在老年代中这叫空间分配担保;

第n次Minor GC
1、 将eden区没有存活的对象,标记清除掉将eden存活的对象+from存活的对象,放到to区;
2、 如果eden区,from区的对象年龄达到阀值,对象会被移到老年代;
1、 年龄阀值默认为15,新生代中的对象每熬过一轮垃圾回收,年龄值就加1;

存活的对象分配到to区后,接着清空Eden区和From区,最后From区和To区交换它们的角色,也就是新的To区就是上次GC清空的From区,新的From区就是上次GC的To区,总之,不管怎样都会保证To区在一轮GC后是空的。

3、老年代(Old)

3.1、介绍

1、 在新生代中经历了多次(具体看虚拟机配置的阀值)GC后仍然存活下来的对象会进入老年代中;
2、 老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢;

3.2、对象进入老年代场景

1、 大对象直接进入老年代引起;

1、 由-XX:PretenureSizeThreshold参数定义;
2、 MinorGC时,经历过多次MinorGC仍存在的对象进入老年代;

1、 由-XX:MaxTenuringThreashold参数定义;
3、 MinorGC时,动态对象年龄判定机制会将对象提前转移老年代年龄从小到大进行累加,当加入某个年龄段后,累加和超过survivor区域-XX:TargetSurvivorRatio的时候,从这个年龄段往上的年龄的对象进入老年代;
4、 MinorGC时,Eden和From区向To区复制时,To区不够大,会直接把对象转移到老年代;

4、永久代(Permanent)

1、 永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,Java虚拟机规范指出可以不进行垃圾收集,一般而言不会进行垃圾回收;
2、 JDK8版本去掉了PermGen区,也就是说JDK8以及之后版本,就没有Permanent区了;

4.1、回收内容

1、 废弃的常量;
2、 无用的类;

4.2、判断废弃常量

一般是判断没有该常量的引用。

4.3、判断无用的类:要以下三个条件都满足

1、 该类所有的实例都已经回收,也就是Java堆中不存在该类的任何实例;
2、 加载该类的ClassLoader已经被回收;
3、 该类对应的java.lang.Class对象没有任何地方呗引用,无法在任何地方通过反射访问该类的方法;

5、GC

5.1、Minor GC

1、 用于清理新生空间;
2、 一旦新创建的对象在eden区放不下的时候,这个时候就触发1次MinorGC;

5.2、Full GC 介绍

1、 用于清理整个堆空间包含New、Old和PermGen;
2、 FullGC比MinorGC要慢,因此应该尽可能减少FullGC的次数;

5.3、Full GC 触发条件

1、 System.gc()被显示调用;
2、 PermGen区(方法区)空间不足,JDK8版本去掉了PermGen区,也就没有这个问题;
3、 老年代空间不足,引起FullGC;
4、 空间分配担保机制可能会触发FullGC;

6、空间分配担保机制

6.1、jdk6版本的空间分配担保

空间担保分配是指在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间 是否 大于新生代所有对象的总空间。
老年代最大可用的连续空间 大于 新生代所有对象的总空间:此次Minor GC是安全的,借空间给年轻代
老年代最大可用的连续空间 小于 新生代所有对象的总空间:
	是否允许担保失败(HandlePromotionFailure)
		true 
			老年代最大可用连续空间 是否 大于历次晋升到老年代的对象的平均大小
				大于:
					尝试进行一次Minor GC,但这次Minor GC依然是有风险的,失败后会重新发起一次Full gc
				小于:
					直接Full GC。
		false 
			直接Full GC

6.1、jdk6 之后版本的空间分配担保

只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。