不是所有的Object都分配在一个区域,它可以进一步的划分,堆可以进一步划分为新生代和老年代,
新生代:
Eden区
Survivor(from)区:
设置Survivor是为了减少送到老年代的对象
Survivor(to)区:
设置两个Survivor区是为了解决碎片化的问题(复制回收算法)
为什么划分为三个区?其实是和垃圾回收有一定关系的.
老年代:
ParOldGen
文档:堆内存分配策略图[和笔记对接].note
链接:http://note.youdao.com/noteshare?id=7c25b18ccf260b31c4de7b64845a6407
(一)新生代
堆中参数配置:
新生代大小: -Xmn20m 表示新生代大小20m(初始和最大)
-XX:SurvivorRatio=8 表示Eden和Survivor的比值,
缺省为8 表示 Eden:From:To= 8:1:1 如果不设置的话Eden:From:To默认是 8比1比1
2 Eden:From:To= 2:1:1
(二)分配原则
刚new出来的对象的时候,当堆里面是空白的时候,一定是优先在Eden区进行分配的,如果Eden区放不下了,大对象会放入老年代(当然也可以进行参数设置,超过这个参数的会自动进入老年代),Eden区中长期存活的对象就会进入老年代
1.对象优先在Eden区分配
注意:新生代初始时就有大小
大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间分配时,虚拟机将发起一次Minor GC。
目前主流的垃圾收集器都会采用分代回收算法,因此需要将堆内存分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC.
简单解释一下为什么会出现这种情况: 因为给 allocation2 分配内存的时候 eden 区内存几乎已经被分配完了,我们刚刚讲了当 Eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC.GC 期间虚拟机又发现 allocation1 无法存入 Survivor 空间,所以只好通过 分配担保机制 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放 allocation1,所以不会出现 Full GC。执行 Minor GC 后,后面分配的对象如果能够存在 eden 区的话,还是会在 eden 区分配内存。
2.大对象直接进入老年代
PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效。
最典型的大对象是那种很长的字符串以及数组。这样做的目的:1.避免大量内存复制,2.避免提前进行垃圾回收,明明内存有空间进行分配。
3.长期存活对象进入老年区
如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor(Survivor1或者是Survivor2)空间中,并将对象年龄设为1(在对象头里面),如果Eden区满了就会发生一次垃圾回收,此时Survivor1区里面的对象如果还存活就会被移动到Survivor2区,同样Survivor2区里面里面还存活的对象会移动至Survivor1区(Survivor1和Survivor2区采用的是复制回收算法),移动完了之后,并且将对象年龄加1 .如此反复,对象在Survivor区中每熬过一次 Minor GC,年龄就增加1,如果年龄达到一定程度(默认的是15),此时对象就会挪到老年代中.
4.对象年龄动态判定
如果Survivor1和Survivor2空间相同年龄的所有对象大小加起来的空间大于Survivor1空间的一半儿,年龄大于或等于该年龄的对象就可以直接进入老年代.
为了更好的适应不同程序的内存情况,虚拟机不是永远要求对象年龄必须达到了某个值才能进入老年代,如果 Survivor 空间中相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需达到要求的年龄。
为什么要这样,参考下面的:
https://www.yuque.com/docs/share/6a9bcddb-8486-4bd7-ac1e-a92aad1f2da7?# 《jvm动态年龄计算规则以及为什么要这样做》