欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JVM之堆的体系结构

程序员文章站 2022-05-18 19:26:17
eden space剩余空间不足分配,且需要分配对象内存不小于eden space总空间的一半,直接分配到老年代,不触发Minor GC。适合-XX:+UseParallelGC、-XX:+UseParallelOldGC,即适合Parallel Scavenge。 ......

一、堆的体系结构

JVM之堆的体系结构

heap 堆一个jvm 实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类字节码文件后,需要把类、方法、常量、变最放到堆内存中,保存所有引用类型的真实信息,以便执行器执行。
堆内存分为三部分:

  • young generation space 新生区 young/new
  • tenure generation space 养老区 old/tenure
  • permanent space 永久代 perm(jdk1.8 修改为metaspace,该区域从jvm的堆内存中移动到系统的本地内存;既jdk1.8的堆体系结构=新生代+老年代+metaspace),永久代在逻辑上在堆内存空间,但在物理上永久代与堆是独立的。方法区是规范,jvm的永久代是实现,元空间也是方法区的一个实现

新生区:新生区是类的诞生、成长、消亡的区域,一个类在该这产生、应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分:伊甸区(eden space)和两个幸存者区(survivor space) 或者是survivor  form 和 survivor  to,所有的类都是在伊甸区被new 出来的。当伊甸园的空间用完时,程序又需要创建对象,jvm 的垃圾回收器将对伊甸园区进行垃圾回收(minor gc ) ,在gc开始的时候,对象只会存在于eden区和名为“from”的survivor区,survivor区“to”是空的。紧接着进行gc,eden区中所有存活的对象都会被复制到“to”,而在“from”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-xx:maxtenuringthreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“to”区域。经过这次gc后,eden区和from区已经被清空。这个时候,“from”和“to”会交换他们的角色,也就是新的“to”就是上次gc前的“from”,新的“from”就是上次gc前的“to”。不管怎样,都会保证名为to的survivor区域是空的。minor gc会一直重复这样的过程,直到“to”区被填满,“to”区被填满之后,会将所有对象移动到年老代中。若老年代也满了,那么这个时候将产生 major gc(full gc),进行老年代的内存清理。若老年代执行了full gc之后发现依然无法释放足够的内存,进行对象的保存,就会产生 oom 异常 outofmemoryerror。

如果出现 java.lang.outofmemoryerror : java heap space 异常,说明java 虚拟机的堆内存不够,原因是:
1、java 虚拟机的堆内存设置不够,可以通过参数 -xms -xmx 来调整
2、代码中创建了大量对象,且长时间不能被垃圾收集器收集(存在被引用),需要我们从代码的角度寻找问题

老年代:经历多次minor  gc 依然存活的对象会进入老年代;连接池的对象一般会进入老年代,常驻内存的内存缓存一般也会进入老年代;

新生代到老年代的一般场景:

  • 1、普通情况下 通过设置该参数 xx:maxtenuringthreshold 
  • 2、分配的对象空间大于eden space。
  • 3、eden space剩余空间不足分配,且需要分配对象内存不小于eden space总空间的一半,直接分配到老年代,不触发minor gc。适合-xx:+useparallelgc、-xx:+useparalleloldgc,即适合parallel scavenge。
  • 4、大对象直接进入老年代,使用-xx:pretenuresizethreshold参数控制,适合-xx:+useserialgc、-xx:+useparnewgc、-xx:+useconcmarksweepgc,即适合serial和parnew收集器。

永久区:永久存储区足一个常驻内存区域,用于存放jdk白身所携带的class , interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾收器回收掉的,关闭jvm 才会释放此区域所占的内存。如果出现 java.lang.outofmemoryerror: permgen space ,说明是 java 虚拟机的永久代 perm 内存设置不够。一般出现这种情况,都是程序启动需要加载大量的第三方 jar 包。例如:在一个tomcat下部署很 多的应用或者大量动态反射生成的类不断被加载,最终导致perml区被填满。
jdkl.6及之前:有永久代,常量池在方法区
jdkl.7:有永久代,但己经逐步“去水久代”,常量池在堆里
jdkl.8 及之后:无永久代,常量池在元空间

二、堆参数调优

默认值:

JVM之堆的体系结构

 JVM之堆的体系结构

参数设置:-xms10m -xmx10m -xx:+printgcdetails

JVM之堆的体系结构