我们说Java是自动进行内存管理的,所谓自动化就是,不需要程序员操心,Java会自动进行内存分配和内存回收这两方面。

0、Minor GC、Major GC和Full GC

  下面会出现这几个概念,所以这里首先介绍一下。

  ①、Minor GC

  也叫Young GC,指的是新生代 GC,发生在新生代(Eden区和Survivor区)的垃圾回收。因为Java对象大多是朝生夕死的,所以 Minor GC 通常很频繁,一般回收速度也很快。

  ②、Major GC

  也叫Old GC,指的是老年代的 GC,发生在老年代的垃圾回收,该区域的对象存活时间比较长,通常来讲,发生 Major GC时,会伴随着一次 Minor GC,而 Major GC 的速度一般会比 Minor GC 慢10倍。

  ③、Full GC

  指的是全区域(整个堆)的垃圾回收,通常来说和 Major GC 是等价的。 

1、对象优先在Eden上分配

  大多数情况下,对象优先在 Eden 上分配。当 Eden 区没有足够的空间进行分配时,虚拟机将会发起一次 Minor GC(新生代GC)。

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

  通常大对象是指需要大量连续内存空间的Java对象,比较典型的就是那种很长的字符串以及数组。

  系统中出现大量大对象是很影响性能的,这样会导致还有不少空间时就提前触发垃圾回收来放置这些对象。

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

  我们知道Java虚拟机是通过分代收集的思想来管理内存,新创建的对象通常放在新生代,除此之外,还有一些对象放在老年代。为了识别哪些对象放在新生代,哪些对象放在老年代,虚拟机给每个对象定义了一个年龄计数器(Age),如果对象在新生代Eden创建,并经历一次 Minor GC 后仍然存活,并且能够被 Survivor 容纳的话,虚拟机会将该对象移动到 Survivor 区域,并将对象的年龄Age+1。

  新生代对象每熬过一次 Minor GC,年龄就增加1,当它的年龄增加到一定阈值时(默认是15岁),就会被晋升到老年代中。

4、空间分配担保原则

   在前面介绍垃圾回收时,我们介绍过现在Java虚拟机采用的是分代回收算法,新生代采用复制收集算法,而老年代采用标记整理,或者标记清除算法。

 

JAVA手动gc虚拟内存 java虚拟机gc_垃圾回收

  新生代内存分为一块 Eden区,和两块 Survivor 区域,当发生一次 Minor GC时,虚拟机会将Eden和一块Survivor区域的所有存活对象复制到另一块Survivor区域,通常情况下,Java对象朝生夕死,一块 Survivor 区域是能够存放GC后剩余的对象的,但是极端情况下,GC后仍然有大量存活的对象,那么一块 Survivor 区域就会存放不下这么多的对象,那么这时候就需要老年代进行分配担保,让无法放入 Survivor 区域的对象直接进入到老年代,当然前提是老年代还有空间能够存放这些对象。但是实际情况是在完成GC之前,是不知道还有多少对象能够存活下来的,所以老年代也无法确认是否能够存放GC后新生代转移过来的对象,那么这该怎么办呢?

  前面我们介绍的都是Minor GC,那么何时会发生 Full GC?

  在发生 Minor GC 时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间,如果大于,则改为 Full GC。如果小于,则查看 HandlePromotionFailure 设置是否允许担保失败,如果允许,那只会进行一次 Minor GC,如果不允许,则也要进行一次 Full GC。

  回到第一个问题,老年代也无法确认是否能够存放GC后新生代转移过来的对象,那么这该怎么办呢?

  也就是取之前每一次回收晋升到老年代对象容量的平均大小作为经验值,然后与老年代剩余空间进行比较,来决定是否进行 Full GC,从而让老年代腾出更多的空间。

  通常情况下,我们会将 HandlePromotionFaile 设置为允许担保失败,这样能够避免频繁的发生 Full GC。