jvm中的堆

Posted nyhhd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm中的堆相关的知识,希望对你有一定的参考价值。

一.Java堆从GC的角度去看,可以分为三个区域,分为是新生代,老年代,永久代(是方法区的实现,但是物理逻辑是和堆在一起的)

  其中新生代占1/3的堆空间,老年代占2/3的堆空间,永久代占得很少,就不进行划分了,他也占了,但是很少很少,新生代占的1/3又分为Eden区(占比8/10),ServivorFrom区(占比1/10),ServivorTo区(占比1/10),大概的占比图如下

                          技术图片

 

  1.gc
    1)如果进行了一次gc后还存活,age+1,然后进入新生代中的s0区
    2)GC会根据区域的剩余内存进行判断是否进行清理
    3)如果age等于15时,进入老年代,长期存活的对象进入老年代
    4)动态年龄判断:如果s0中有一部份的对象的内存大于它的50%,则将年龄大的放进老年代

  2.使用gcroot判断对象是否可达,来判断对象是否可被回收(是否为垃圾),哪些可以被作为gcroot呢:

    1、栈(栈帧中的本地变量表)中对象的引用。

    2、方法区中的静态成员。

    3、方法区中的常量引用的对象(全局变量)。

    4、本地方法栈中JNI(一般说的Native方法)引用的对象。

 

1.新生代

  我们新创建的对象(除了大对象,大对象是直接放进了老年代)都是放在新生代中的,由于JVM会频繁的创建对象,所以就会频繁的触发GC,新生代时的GC叫做MinorGC

新生代中分为了三个区域,分别时Ened、ServivorTo、ServivorFrom(这两空间交替变成ServivorTo和ServivorFrom的)

  Ened:我们新创建的对象首先就会放入到Ened区,当Ened区的内存不足时会触发MinorGC

  ServivorTo:存放上一次MinorGC的幸存者,也是下一次的ServivorFrom区

  ServivorFrom:存放的是上一次MinorGC的幸存者,在上一次中他是ServivorTo区,他在这一次中充当被扫描者的角色

其实从上面的几个介绍来看,可能就只能理解Ened是干嘛的,如果了解了MinorGC的流程就会很清楚了

 

MinorGCC复制算法:将空间划分为两份,一个预留,一个实际,在进行GC时,将预留的开启,将没被删除的放进预留的内存块,将实际的转换为预留的

MinorGCC的具体过程是采用复制算法实现的,具体步骤如下:

  1、首先会把Ened区与ServivorFrom区中存活的对象复制到ServivorTo区中去。这里会将达到了老年代的标准的对象复制到老年代区去,然后整体对象的标准年龄+1(15为老年代的标准),如果ServivorTo的内存不足的情况,存活的对象就直接全部复制到老年代

  2、清空Ened区与ServivorFrom区

  3、将ServivorTo区与ServivorFrom区互换,原本的ServivorTo区成为了下一次ServivorFrom区,然后下一次他里面的对象又要被复制到下一次的ServivorTo区中区

 

2.老年代

  老年代主要存放的就是长生命周期的对象和大对象,不会频繁出发GC了,老年代的GC叫做MajorGC,在进行老年代GC之前,他会调用新生代的GC一次,然后将那些要存放到老年代的对象都复制过来,如果在新生代GC后,老年代的空间不足,那么就会触发MajorGC

  老年的GC采用的是标记清除法,标记清除算法:在GC的过程中,将要删除的标记删除,但会产生内存碎片

  他会去扫描所有的对象并且标记存活的对象,然后回收掉所有未标记的对象。MajGC因为要扫描所有的对象,所以耗时会较长,而且标记清除法也容易产生内存碎片,老年代内存空间不足时,会触发OOM

 

3.永久代

永久代主要保存的是Class和元数据信息,Class在类加载时被放入永久代,永久代不会触发GC,因为他不会GC,所以他的内存会随着加载Class文件的增加而增加,加载的Class文件过多时就会OOM,比如Tomcat引用的jar文件过多时就会导致JVM内存不足而无法启动

在1.8之前,永久代是用的JVM虚拟机的内存,所以他的实际可用内存就受到了JVM内存的限制,1.8之后用的是操作系统的内存

 

以上是关于jvm中的堆的主要内容,如果未能解决你的问题,请参考以下文章

java中堆和栈的区别!!!!

JVM中的堆和非堆内存

jvm_Java对象在堆中的内存结构

JVM中的堆的新生代老年代永久代详解

一篇文章帮你搞定JVM中的堆

如何减少 JVM 中的已提交堆内存