内存分配策略与回收策略
给对象分配内存以及回收给对象分配的内存。对象的内存分配绝大部分主要是在Java堆上,有一部分特殊的就是JIT编译器,经过JIT编译后被拆散为标量类型并间接地在栈上分配内存。
对象主要分配集中在新生代的Eden区,如果启动了本地线程分配缓冲,按照线程优先在TLAB上分配。少数分配在老年代,分配在哪里取决于当前使用的垃圾回收器组合和虚拟机中相关内存参数的设定。
- 新生代GC :Minor GC,发生在新生代的垃圾回收动作,非常频繁,速度很快。
- 老年代GC :Major GC/Full GC,指发生在老年代,发生了Major GC,经常会出现至少一次的Minor GC,但不是绝对的,在parallel scavenge收集器的收集策略里就有直接进行Major gc的策略选择过程。Major GC的速度比Minor GC慢10倍以上。
1、对象优先在新生代的Eden区分配
一般情况下,新对象优先在新生代的Eden区分配,当eden区没有足够的内存空间时,虚拟机将发起一次Minor GC.
2、大对象直接进入老年代
大对象指,需要大量连续内存空间的Java 对象。典型的就是很长的字符串以及数组。
3、长期存活的对象将进入老年代
由于虚拟机采用了分代思想管理内存,那么内存回收时就必须能识别那些对象应放在新生代,那些对象放在老年代。为了做到这一点,Java虚拟机给每个对象定义了一个对象年龄计数器(Age)。
如果对象在Eden区出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且年龄对象设为1.对象在survivor区中每熬过一次minor GC,年龄对象就加1;当他的年龄增加到一定程度,默认为15岁,就将晋升到老年代中。对象晋升老年代的阀值可以通过-XX:MaxTenuringThreshold设置。
4、动态对象年龄判定
为了更好的适应不同的内存状况,虚拟机并不是永远的要求对象的年龄必须到达阀值才能进入老年代。
如果 在survivor空间中相同年龄所有对象大小的总和大于survivor空间的一半,那么这些对象就直接进入老年代。
5、空间分配担保
在发生minor gc之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间。如果条件成立,那么minor gc 可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。
如果允许,那么继续查看老年代的最大可用的连续内存是否大于历次晋升到老年代对象的平均大小,
如果大于,那么尝试进行一次minor gc,尽管是有风险的,
如果小于或者不允许,那么直接进行一次Full GC.
版权声明:本文为博主原创文章,未经博主允许不得转载。