JVM运行时的内存分配

java中的堆,一般分为三大部分:新生代、老年代、永久代。

一、新生代(Young区)

  1. 主要用来存放新生(new)的对象。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁的触发 MinorGC 进行垃圾回收。
  2. 新生代分为三个区:
    (1)Eden区:Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。
    (2)SurvivorTo:保留了一次MinorGC过程中的幸存者。
    (3)SurvivorFrom:上一次GC的幸存者,作为这一次GC的被扫描者。

二、老年代(Old区)

  1. 主要存放应用程序中生命周期长的内存对象。老年代的对象比较稳定,所以MajorGC不会频繁执行。
  2. 在进行MajorGC前一般都先进行了一次MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次MajorGC进行垃圾回收腾出空间。
  3. 当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。

三、永久代

  1. 在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。
  2. 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

四、Minor GC

  1. MInor GC:清理年轻代
  2. 触发条件:
    (1)当新生代无法为新生对象分配内存空间的时候,会触发Minor GC,比如Eden区满了会触发一次
    (2)新创建的对象大小>Eden所剩空间

发生MinorGC,对象会从Eden区进入Survivor区,如果Survivor区放不下从Eden区过来的对象时,此时会使用分配担保机制将对象直接移动到年老代。

  1. MinorGC的过程:复制->清空->互换
  2. MinorGC采用复制算法
    (1)Eden 、SurvivorFrom 复制到SurvivorTo ,年龄 + 1

首先,产生一个新对象,新对象优先在Eden区分配。如果Eden区放不下这个对象,虚拟机会使用复制算法发生一次Minor GC,清除掉无用对象,同时将存活对象移动到Survivor的其中一个区(fromspace区或者tospace区)。

虚拟机会给每个对象定义一个对象年龄(Age)计数器,对象在Survivor区中每“熬过”一次GC,年龄就会+1。待到年龄到达一定岁数(默认是15岁)。

如果有对象的年龄以及达到了老年的标准,则赋值到老年代区,同时把这些对象的年龄+1。如果 SurvivorTo 不 够位置了就放到老年区。

(2)清空Eden 、SurvivorFrom
(3)SurvivorTo和 SurvivorFrom互换,原SurvivorTo成为下一次GC时的SurvivorFrom 区。

五、Major GC

  1. Major GC:清理老年代
  2. 触发条件:回收老年代,通常至少经历过一次Minor GC
  3. MajorGC 采用标记清除算法

六、Full GC

  1. Full GC 是清理整个堆空间,包括年轻代和老年代
    为什么这样说,因为Major GC发生过程常常伴随一次Minor,因此Full GC可以看做是Major GC+Minor GC共同进行的一整个过程,清理了整个堆上的对象。
  2. 触发条件:
    (1)调用System.gc时,系统建议执行Full GC,但是不必然执行
    (2)老年代空间不足
    (3)方法区(永久代)空间不足
    (4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
    (5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

你可能感兴趣的:(JVM运行时的内存分配)