JVM内存分配机制与回收策略选择-JVM学习笔记(2)

Java体系中的自动内存管理主要包括了2个方面:java

  1. 自动地给对象分配内存。
  2. 自动地回收分配给对象地内存。

本文也围绕这两个点展开 算法

一. 内存分配规则

1.优先在Eden区分配

大多数状况下,JVM会在 Eden 区优先分配对象,若是 Eden 没有足够的空间,则进行一次 Minor GC 。经过参数 -XX:+PrintGCDetails 可让虚拟机在进行垃圾回收时打印日志,方便咱们看到回收先后的内存占用状况。优化

例: 假如如今内存大小指定以下:spa

  • 新生代 ->10M
    • Eden区 -> 8M
    • from区 -> 1M
    • to 区 -> 1M
  • 老年代 -> 10M

而后咱们又前后在代码中建立4个对象:3d

byte[] byte1 = new byte[2MB];
byte[] byte2 = new byte[2MB];
byte[] byte3 = new byte[2MB];
byte[] byte4 = new byte[4MB];
复制代码

当建立完第三个对象后,Eden区已经用掉了6M的空间来存放 byte1,byte2,byte3 三个对象,再建立第四个对象时,Eden区加上一个from区已经放不下了,如先前所述,此时会触发一次 MinorGC ,将三个2MB的对象转移到老年代中,腾出Eden区的空间给 第四个对象。日志

因此,执行后的内存状况以下:code

  • 新生代 -> 10M
    • Eden 区 -> 8M (剩余4M) 存放 byte4
    • from区  -> 1M
    • to区      -> 1M
  • 老年代 -> 10M (剩余4M) 存放byte1,byte2,byte3。

2.大对象直接进入老年代

经过 -XX:PretentureSizeThreshold 参数设置大于这个值的对象直接分配到老年代。cdn

3.长期存活的对象进入老年代

怎么算是长期存活 ?对象

JVM给每一个对象定义了一个 对象年龄计数器 。当对象一开始被分配到新生代Eden区,通过一次  MniorGC 
后仍然存活,而且Survivor区可以容纳它,则此对象被转移到 Survivor 区,年龄变为1。
Survivor 区中的对象没熬过一次 MniorGC ,年龄就涨1,当年龄达到咱们设定的年龄阈值(JVM默认设定15)时,就会进入老年代。15岁就已经步入老年....
年龄阈值可经过参数 -XX:MaxTenuringThreshold = 指定值 来设定。
blog

对对象年龄断定的优化

JVM中,若是Survivor区中的相同年龄全部对象的大小总和大于Survivor空间的一半,那么这些同学们就直接进入老年代。无须等到上面的年龄阈值。

二. 空间分配担保机制与回收策略(Mnior GC仍是Full GC)

首先介绍一下 Mnior GC  和 Full GC  的区别:

MniorGC :  发生在新生代的垃圾回收活动,因为新生代的Java对象 短命的特性,这种垃圾回收活动频繁,回收速度较快。(就像扫碎纸屑) Full GC : 发生在老年的垃圾回收活动,不过出现一次  Full GC,也会伴随着一次 MniorGC,因为老年代中的对象基本都是大对象,长命,因此Full GC的速度比Mnior GC 的速度慢10倍以上。(就像搬大石头)

新生代的垃圾回收算法采用的是 复制算法 ,当进行一次 Mnior GC 时,会将新生代的活动区域( Eden区 和Survivor中的 From区 )中的存活对象复制到 Survivor中的 to区 ,若是 to 区的内存不足以放下这些对象,那么这时就须要老年代出马,进行分配担保机制,将放不下的对象放到老年代。
    因此,在进行 Monior GC  前,JVM会作如下流程的检查,以确认老年代是否可以放得下那些对象,来选择进行 Mnior GC  仍是  Full GC 。

image.png

Reference:
深刻理解Java虚拟机

image.png
相关文章
相关标签/搜索