Java虚拟机(二)——Java堆内存划分

堆内存介绍

  在《Java虚拟机(一)——Java内存区域划分》一文中介绍了Java 虚拟机 内存划分的内容,其中讲到堆内存(Heap)。对于大多数应用来说,Java堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块。此内存区域的唯一目的就是存在对象实例,几乎所有的对象实例都在这里分配内存。这个区域也是Java 垃圾收集器管理的主要区域,因此很多时候也被称为”GC堆”。所以堆内存非常重要,我们有必要去了解它的细节,这对我们深入了解Java 垃圾回收机制非常有帮助。

堆内存划分

在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:EdenFrom SurvivorTo Survivor
这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

堆的内存模型大致如下图所示:

Java堆内存模型

从图中可以看出: 堆大小 = 新生代 + 老年代

默认情况下,

新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 
Eden : from : to = 8 : 1 : 1 

JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的
因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

堆的垃圾回收方式

Java 中的堆也是 GC 收集垃圾的主要区域。GC 分为两种:Minor GC、Full GC ( 或称为 Major GC )。

Minor GC

Minor GC 是发生在新生代中的垃圾收集动作,所采用的是复制算法
新生代几乎是所有 Java 对象出生的地方,即 Java 对象申请的内存以及存放都是在这个地方。Java 中的大部分对象通常不需长久存活,具有朝生夕灭的性质。
当一个对象被判定为 “死亡” 的时候,GC 就有责任来回收掉这部分对象的内存空间。新生代是 GC 收集垃圾的频繁区域。

回收过程如下:

  当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳(上面已经假设为 from 区域,这里应为 to 区域,即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即 from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。
但这也不是一定的,对于一些较大的对象 ( 即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代。

Full GC

Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法
现实的生活中,老年代的人通常会比新生代的人 “早死”。堆内存中的老年代(Old)不同于这个,老年代里面的对象几乎个个都是在 Survivor 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。因此,Full GC 发生的次数不会有 Minor GC 那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长,一般是Minor GC的 10倍以上。
另外,标记-清除算法收集垃圾的时候会产生许多的内存碎片 ( 即不连续的内存空间 ),此后需要为较大的对象分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。
关于垃圾收集算法的详细内容请参见《Java虚拟机(三)——垃圾收集器》。

你可能感兴趣的:(Java,深入学习Java虚拟机)